c# - realizar - LINQ to SQL y un total acumulado de resultados ordenados
realizar consultas en c# (5)
El agregado se puede usar para obtener un total acumulado también:
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;
});
Quiero mostrar el historial contable de un cliente en DataGridView
y quiero tener una columna que muestre el total acumulado de su saldo. La antigua forma en que lo hice fue obtener los datos, recorrer los datos y agregar filas al DataGridView
uno a uno y calcular el total acumulado en ese momento. Cojo. Prefiero usar LINQ to SQL, o LINQ si no es posible con LINQ to SQL, para calcular los totales acumulados, así puedo simplemente establecer DataGridView.DataSource
en mis datos.
Este es un ejemplo súper simplificado de lo que estoy buscando. Digamos 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 una declaración L2S o LINQ que pueda generar resultados que se vean así:
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
Tenga en cuenta que puede haber varios elementos con la misma fecha (12-02-2009). Los resultados deben ordenarse por fecha antes de calcular los totales acumulados. Supongo que esto significa que necesitaré dos declaraciones, una para obtener los datos y ordenarlos, y otra para realizar el cálculo del total acumulado.
Esperaba que Aggregate
hiciera el truco, pero no funciona como esperaba. O tal vez simplemente no pude resolverlo.
Esta question parecía ir después de lo mismo que quería, pero no veo cómo la respuesta aceptada / única resuelve mi problema.
¿Alguna idea sobre cómo llevarlo a cabo?
Editar Combinando las respuestas de Alex y DOK, esto es con lo que terminé:
decimal runningTotal = 0;
var results = FetchDataFromDatabase()
.OrderBy(item => item.Date)
.Select(item => new Item
{
Amount = item.Amount,
Date = item.Date,
RunningTotal = runningTotal += item.Amount
});
En caso de que aún no se haya respondido, tengo una solución que he estado usando en mis proyectos. Esto es bastante similar a un grupo con particiones Oracle. La clave es hacer que la cláusula where en el total acumulado coincida con la lista orig y luego agruparla 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();
Qué tal 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();
}
}
}
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
}
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));
}
}