LINQ to SQL и промежуточный итог по упорядоченным результатам - PullRequest
35 голосов
/ 02 декабря 2009

Я хочу отобразить историю учета клиента в 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 справится, но это не сработает, как я надеялся. Или, может быть, я просто не мог понять это.

Этот вопрос , похоже, преследовал то же, что и я, но я не понимаю, как принятый / единственный ответ решает мою проблему.

Есть идеи, как это осуществить?

Редактировать Комбинируя ответы Алекса и 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 ]

39 голосов
/ 02 декабря 2009

Использование замыканий и анонимный метод:

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
}
26 голосов
/ 02 декабря 2009

Как насчет этого: (кредит идет на этот источник )

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();
        }
    }
}
6 голосов
/ 01 октября 2014

Если на этот вопрос еще не ответили, у меня есть решение, которое я использовал в своих проектах. Это очень похоже на секционированную группу 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();
1 голос
/ 12 апреля 2013

Агрегат также может быть использован для получения промежуточного итога:

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;
});
0 голосов
/ 16 августа 2017
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));
    }
}
...