34


13

LINQ to SQLおよび順序付けられた結果の積算合計

「DataGridView」に顧客の会計履歴を表示し、残高の現在の合計を表示する列が必要です。 私がこれをした古い方法は、データを取得し、データをループし、 `DataGridView`に行を1つずつ追加し、その時点での実行合計を計算することでした。 ラメ。 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)のアイテムが複数存在する可能性があることに注意してください。 実行中の合計を計算する前に、結果を日付でソートする必要があります。 これは、データを取得してソートするためのステートメントと、実行中の合計計算を実行するためのステートメントの2つのステートメントが必要になることを意味すると推測しています。

「Aggregate」がこのトリックを実行することを期待していましたが、期待していたようには機能しません。 または多分私はちょうどそれを理解できなかった。

これはhttps://stackoverflow.com/questions/1576816/linq-running-total-and-sub-total[question]が私が望んだのと同じことを追求しているように見えましたが、受け入れられた/唯一の答えがどのように見えるかわかりません私の問題を解決します。

これをやめる方法について何かアイデアはありますか?

*編集*アレックスと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
    });

5 Answer


38


クロージャーと匿名メソッドの使用:

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


25


これはどうですか:(クレジットはhttp://www.straferight.com/forums/pc-hardware-software/176318-linq-sql-thread.html [このソース]にあります)

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 list = new List() { 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();
        }
    }
}


5


まだ回答されていない場合は、プロジェクトで使用しているソリューションがあります。 これは、Oracleパーティショングループに非常に似ています。 重要なのは、現在の合計のwhere句を元のリストと一致させ、それを日付でグループ化することです。

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


1


集計を使用して、現在の合計を取得することもできます。

var src = new [] { 1, 4, 3, 2 };
var running = src.Aggregate(new List(), (a, i) => {
    a.Add(a.Count == 0 ? i : a.Last() + i);
    return a;
});


0


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var list = new List{1, 5, 4, 6, 8, 11, 3, 12};

        int running_total = 0;

        list.ForEach(x=> Console.WriteLine(running_total = x+running_total));
    }
}