Подтвердить что ты не робот

С#: Как использовать метод Enumerable.Aggregate

Давайте скажем, что у меня есть этот ампутированный класс Person:

class Person
{
    public int Age { get; set; }
    public string Country { get; set; }

    public int SOReputation { get; set; }
    public TimeSpan TimeSpentOnSO { get; set; }

    ...
}

Затем я могу группировать по Age и Country следующим образом:

    var groups = aListOfPeople.GroupBy(x => new { x.Country, x.Age });

Затем я могу вывести все группы с их итогом репутаций следующим образом:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Sum(x => x.SOReputation));

Мой вопрос: как я могу получить сумму свойства TimeSpentOnSO? Метод Sum не будет работать в этом случае, поскольку он предназначен только для int и тому подобного. Я думал, что могу использовать метод Aggregate, но просто серьезно не могу понять, как его использовать... Я пробую все виды свойств и типов в разных комбинациях, но компилятор просто не узнает его.

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(  what goes here??  ));

Я полностью пропустил метод Aggregate? Или что происходит? Это какой-то другой метод, который я должен использовать вместо этого? Или мне нужно написать собственный вариант Sum для TimeSpan s?

И чтобы добавить к беспорядку, что, если Person является анонимным классом, результатом является, например, оператор Select или GroupJoin?


Просто понял, что я мог бы сделать метод Aggregate, если я сначала выполнил Select в свойстве TimeSpan... но я нахожу, что это раздражает... Все еще не чувствую, что понимаю этот метод вообще...

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Select(x => x.TimeSpentOnSO)
        g.Aggregate((sum, x) => sum + y));
4b9b3361

Ответ 1

Комбинация ответов Криса и Дэниелса решила его для меня. Мне нужно было инициализировать TimeSpan, и я делал что-то в неправильном порядке. Решение:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(TimeSpan.Zero, (sum, x) => sum + x.TimeSpentOnSO));

Спасибо!

И также... D'oh!

Ответ 2

List<TimeSpan> list = new List<TimeSpan>
    {
        new TimeSpan(1),
        new TimeSpan(2),
        new TimeSpan(3)
    };

TimeSpan total = list.Aggregate(TimeSpan.Zero, (sum, value) => sum.Add(value));

Debug.Assert(total.Ticks == 6);

Ответ 3

g.Aggregate(TimeSpan.Zero, (i, p) => i + p.TimeSpentOnSO)

В принципе, первым аргументом для Aggregate является инициализатор, который используется как первое значение "i" в функции, переданной во втором аргументе. Он будет перебирать список, и каждый раз "i" будет содержать общее количество.

Например:

List<int> nums = new List<int>{1,2,3,4,5};

nums.Aggregate(0, (x,y) => x + y); // sums up the numbers, starting with 0 => 15
nums.Aggregate(0, (x,y) => x * y); // multiplies the numbers, starting with 0 => 0, because anything multiplied by 0 is 0
nums.Aggregate(1, (x,y) => x * y); // multiplies the numbers, starting with 1 => 120

Ответ 4

Вы можете написать метод TimeSpan Sum...

public static TimeSpan Sum(this IEnumerable<TimeSpan> times)
{
    return TimeSpan.FromTicks(times.Sum(t => t.Ticks));
}
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source,
    Func<TSource, TimeSpan> selector)
{
    return TimeSpan.FromTicks(source.Sum(t => selector(t).Ticks));
}

В качестве альтернативы MiscUtil имеет общие методы Sum, поэтому Sum должен работать только с TimeSpan (поскольку существует оператор TimeSpan+TimeSpan=>TimeSpan).

Просто пожалуйста не говорите мне номер... это меня пугает...

Ответ 5

Вы могли бы суммировать одно из свойств Total TimeSpan. Например, вы можете получить представленное TotalHours время, затраченное на SO следующим образом:

g.Sum(x => x.SOReputation.TotalHours)

Я считаю, что это даст вам результат, который вы ищете, но с оговоркой, что вам нужно будет поместить единицы измерения в соответствии с тем, что вам нужно (часы, минуты, секунды, дни и т.д.)