LINQ to SQL和排序结果的累计

x8diyxa7  于 2022-12-06  发布在  其他
关注(0)|答案(6)|浏览(163)

我想在DataGridView中显示一个客户的会计历史记录,并希望有一个列来显示他们余额的运行总数。我以前的方法是获取数据,循环数据,然后向DataGridView中逐个添加行,并计算运行总数。糟糕。我更愿意使用LINQ to SQL,或者LINQ(如果无法使用LINQtoSQL)来计算运行总数,这样我就可以将DataGridView.DataSource设置为我的数据。
这是一个非常简单的例子,假设我有下面的类。

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

我想要一个L2 S或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
    });
mm9b1k5b

mm9b1k5b1#

使用闭包和匿名方法:

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
}
ejk8hzay

ejk8hzay2#

不如这样吧:(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();
        }
    }
}
qacovj5a

qacovj5a3#

如果这个问题还没有得到回答,我有一个解决方案,我一直在我的项目中使用。这是非常类似于Oracle分区组。关键是让运行总数中的where子句匹配orig列表,然后按日期分组。

var itemList = GetItemsFromDBYadaYadaYada();

var withRuningTotals = from i in itemList    
                       select new {i.Date, i.Amount,    
                              RunningTotal = itemList.Where( x=> x.Date == i.Date).
                                                      GroupBy(x=> x.Date).
                                                      Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single()};
ni65a41a

ni65a41a4#

聚合也可用于获取运行总计:

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;
});
olmpazwi

olmpazwi5#

大多数其他的解决方案(在对象中正确设置运行总数)都依赖于一个副作用变量,这不符合函数式编码和.Aggregate()之类的精神。
(NB- 此解决方案与其他解决方案一样在客户端上运行,因此可能不是您所需的最佳解决方案。)

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;
        });
yrdbyhpb

yrdbyhpb6#

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));
    }
}

相关问题