Quiero mostrar un cliente de contabilidad de la historia en un DataGridView y quiero tener una columna que muestra el total de su balance. La vieja manera en que lo hice, esto fue por la obtención de los datos, el bucle a través de los datos, y añadir filas a la DataGridView, uno por uno, y calcular el total de ejecución en ese momento. Cojo. Me gustaría mucho usar LINQ to SQL, o LINQ si no es posible con LINQ to SQL, para averiguar los totales así que sólo puedo establecer DataGridView.DataSource a mis datos.

Este es un super-ejemplo simplificado de lo que estoy disparando para. Decir que tengo la siguiente clase.

class Item
{
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public decimal RunningTotal { get; set; }
}

Me gustaría un L2S, o LINQ, declaración que podría generar resultados que se parecen a esto:

   Date       Amount  RunningTotal
12-01-2009      5          5
12-02-2009     -5          0
12-02-2009     10         10
12-03-2009      5         15
12-04-2009    -15          0

Aviso de que puede haber varios elementos con la misma fecha (12-02-2009). Los resultados deben ser ordenados por fecha antes de la ejecución totales se calculan. Supongo que esto significa que se necesitan dos declaraciones, una para los datos y ordenarla y un segundo para realizar el total de ejecución de cálculo.

Tenía la esperanza de Aggregate que hacer el truco, pero no funciona como yo esperaba. O tal vez yo no podía entenderlo.

Este pregunta parecía ir después de la misma cosa que yo quería, pero yo no veo cómo la aceptación de los/única respuesta que soluciona mi problema.

Cualquier idea sobre cómo sacar esto?

Editar
Peinar las respuestas de Alex y DOK, esto es lo que terminó con:

decimal runningTotal = 0;
var results = FetchDataFromDatabase()
    .OrderBy(item => item.Date)
    .Select(item => new Item
    {
        Amount = item.Amount,
        Date = item.Date,
        RunningTotal = runningTotal += item.Amount
    });
  • Gracias por la nueva herramienta! : Totalactualizado = totalactualizado += item.Cantidad
  • No esta solución la fuerza de ejecución a ser en el cliente? (es decir, que se tiene que tirar abajo todo el conjunto de resultados a obtener la respuesta correcta?) — parece que algo como esto iba a ser mucho más eficientes si se hubiera hecho en el servidor SQL server…
  • El uso de una variable externa a la consulta es muy peligroso! Porque results variable es de IEnumerable tipo, su ejecución será diferido hasta más tarde. Si cambia el valor de runningTotal antes de eso, su consulta resultante no ser correctos ya. Para estar seguro que usted necesita para enumerar inmediatamente (a la lista o matriz). Yo no veo nada malo aquí con el uso de un simple foreach bucle.
  • EXACTAMENTE el problema que se intenta resolver. Gracias por preguntar esto hace seis años!
InformationsquelleAutor Ecyrb | 2009-12-02

5 Comentarios

  1. 39

    El uso de cierres y método anónimo:

    List<Item> myList = FetchDataFromDatabase();
    
    decimal currentTotal = 0;
    var query = myList
                   .OrderBy(i => i.Date)
                   .Select(i => 
                               {
                                 currentTotal += i.Amount;
                                 return new { 
                                                Date = i.Date, 
                                                Amount = i.Amount, 
                                                RunningTotal = currentTotal 
                                            };
                               }
                          );
    foreach (var item in query)
    {
        //do with item
    }
    • Me gustaría poder marcar a usted tanto como la respuesta! Su respuesta fue fácil de entender y con mi ejemplo. Me gusta cómo DOK incrementos de la currentTotal en línea, durante la misión, sin embargo.
    • +1 SOF debe tener opciones para el marcado de respuestas múltiples.
    • He intentado esto con Linq to entities (EF) y obtener una «Una expresión lambda con una declaración cuerpo no puede ser convertido a un árbol de expresión» error de compilación. Es que en particular a la EF como contraposición a L2O?
    • Tenga en cuenta que esto termina siendo malo si utiliza el resultado de la consulta en varias ocasiones. Esta pregunta es un resultado de esto. Se pueden resolver mediante la adición de un .ToList() a la final de la consulta.
    • Esta solución será la fuerza de la ejecución de estar en el cliente (es decir, que se tiene que tirar abajo todo el conjunto de resultados a obtener la respuesta correcta) — parece que algo como esto iba a ser mucho más eficientes si se hubiera hecho en el servidor SQL server…
    • se dice que la única forma en que esto funciona es que si usted tira de todo el conjunto de datos hacia el cliente es lo primero (tenga en cuenta que el almacenar el conjunto de datos en una lista y no en un IQueryable < t > o IEnumerable). Tiene que haber una mejor manera.

  2. 26

    Cómo sobre esto: (el crédito va a esta fuente)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            delegate string CreateGroupingDelegate(int i);
    
            static void Main(string[] args)
            {
                List<int> list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 69, 2007};
                int running_total = 0;
    
                var result_set =
                    from x in list
                    select new
                    {
                        num = x,
                        running_total = (running_total = running_total + x)
                    };
    
                foreach (var v in result_set)
                {
                    Console.WriteLine( "list element: {0}, total so far: {1}",
                        v.num,
                        v.running_total);
                }
    
                Console.ReadLine();
            }
        }
    }
    • Gracias! Me gusta cómo asignar running_total en línea. Eso es bastante ingenioso.
    • running_total = (running_total = running_total + x) => la Mente de soplado. Seguramente va a recordar esto para la próxima vez 🙂
    • genial! Funciona con fuertemente tipo de objetos, no sólo los tipos anónimos
    • Tenga en cuenta que esto termina siendo malo si utiliza el resultado de la consulta en varias ocasiones. Esta pregunta es un resultado de esto. Se pueden resolver mediante la adición de un .ToList() a la final de la consulta.
    • Este es otro de cliente única solución (que requiere la enumeración de todo el conjunto de datos en el cliente-esto va a chupar para grandes conjuntos de datos). 🙁
  3. 6

    En caso de que esto no ha sido contestado, yo tengo una solución que he estado usando en mis proyectos. Esto es bastante similar a la de un Oráculo con particiones grupo. La clave es tener la cláusula where en el total de ejecución coincide con el orig lista, entonces el grupo por fecha.

    var itemList = GetItemsFromDBYadaYadaYada();
    
    var withRuningTotals = from i in itemList    
                           select i.Date, i.Amount,    
                                  Runningtotal = itemList.Where( x=> x.Date == i.Date).
                                                          GroupBy(x=> x.Date).
                                                          Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single();
    • Interesante. Parece que esto iba a descargar los datos a la base de datos correctamente.
  4. 1

    Agregado puede ser usado para obtener un total de ejecución así:

    var src = new [] { 1, 4, 3, 2 };
    var running = src.Aggregate(new List<int>(), (a, i) => {
        a.Add(a.Count == 0 ? i : a.Last() + i);
        return a;
    });
  5. 0
    using System;
    using System.Linq;
    using System.Collections.Generic;
    
    public class Program
    {
        public static void Main()
        {
            var list = new List<int>{1, 5, 4, 6, 8, 11, 3, 12};
    
            int running_total = 0;
    
            list.ForEach(x=> Console.WriteLine(running_total = x+running_total));
        }
    }

Dejar respuesta

Please enter your comment!
Please enter your name here