我想在DataGridView
中显示客户的会计历史记录,我希望有一个列显示其余额的运行总计。我这样做的旧方法是获取数据,循环遍历数据,然后逐行向DataGridView
添加行并计算当时的运行总计。瘸。我更倾向于使用LINQ to SQL,或者如果LINQ to SQL不可能使用LINQ来计算运行总数,那么我可以将DataGridView.DataSource
设置为我的数据。
这是我正在拍摄的一个超级简化的例子。说我有以下课程。
class Item
{
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public decimal RunningTotal { get; set; }
}
我想要一个可以产生如下结果的L2S或LINQ语句:
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
请注意,可能有多个项目具有相同的日期(12-02-2009)。在计算运行总计之前,应按日期对结果进行排序。我猜这意味着我需要两个语句,一个用于获取数据并对其进行排序,另一个用于执行运行总计算。
我希望Aggregate
可以做到这一点,但它并不像我希望的那样有效。或者也许我无法理解它。
这question似乎跟我想要的一样,但我不知道接受/唯一的答案如何解决我的问题。
关于如何解决此问题的任何想法?
修改 结合Alex和DOK的答案,这就是我最终的结果:
decimal runningTotal = 0;
var results = FetchDataFromDatabase()
.OrderBy(item => item.Date)
.Select(item => new Item
{
Amount = item.Amount,
Date = item.Date,
RunningTotal = runningTotal += item.Amount
});
答案 0 :(得分:39)
使用闭包和匿名方法:
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
}
答案 1 :(得分:26)
这个怎么样:(信用转到this source)
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();
}
}
}
答案 2 :(得分:5)
如果还没有回答,我有一个解决方案,我一直在我的项目中使用。这与Oracle分区组非常相似。关键是让运行总计中的where子句与orig列表匹配,然后按日期对其进行分组。
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();
答案 3 :(得分:1)
聚合也可用于获取运行总计:
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;
});
答案 4 :(得分: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));
}
}
答案 5 :(得分:0)
对此的大多数其他答案(正确设置对象内的运行总数)依赖于副作用变量,这不符合功能编码和 .Aggregate()
之类的精神。此解决方案消除了副作用变量。
(注意 - 此解决方案将像其他答案一样在客户端上运行,因此可能不是您需要的最佳选择。)
var results = FetchDataFromDatabase()
.OrderBy(item => item.Date)
.Aggregate(new List<Item>(), (list, i) =>
{
var item = new Item
{
Amount = i.Amount,
Date = i.Date,
RunningTotal = i.Amount + (list.LastOrDefault()?.RunningTotal ?? 0)
};
return list.Append(item).ToList();
// Or, possibly more efficient:
// list.Add(item);
// return list;
});