簡體   English   中英

LINQ to SQL 和有序結果的運行總計

[英]LINQ to SQL and a running total on ordered results

我想在DataGridView顯示客戶的會計歷史記錄,並且我想有一列顯示其余額的運行總計。 我這樣做的舊方法是獲取數據,遍歷數據,然后將行一一添加到DataGridView並計算當時的運行總數。 瘸。 我更願意使用 LINQ to SQL 或 LINQ(如果 LINQ to SQL 不可能的話)來計算運行總數,這樣我就可以將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可以解決問題,但它並不像我希望的那樣工作。 或者,也許我只是想不通。

這個問題似乎和我想要的一樣,但我不明白接受/唯一的答案如何解決我的問題。

關於如何解決這個問題的任何想法?

編輯結合 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
    });

使用閉包和匿名方法:

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

如果這還沒有得到回答,我有一個我一直在我的項目中使用的解決方案。 這與 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();

Aggregate 也可用於獲取運行總計:

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

對此的大多數其他答案(正確設置對象內的運行總數)依賴於副作用變量,這不符合功能編碼和.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;
        });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM