19

假设我有这个截肢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为 s 编写自己的变体TimeSpan

更糟糕的是,如果 Person 是一个匿名类,例如 aSelectGroupJoin语句的结果,该怎么办?


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

5 回答 5

24
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);
于 2009-06-09T13:53:06.767 回答
14
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
于 2009-06-09T13:54:26.610 回答
2

克里斯和丹尼尔斯的答案组合为我解决了这个问题。我需要初始化 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));

谢谢!

还有……哦!

于 2009-06-09T14:02:23.113 回答
1

你可以写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定义了运算符)。

只是不要告诉我数字...它会吓到我...

于 2009-06-09T13:51:36.817 回答
0

您可以对 TimeSpan 的 Total 属性之一求和。例如,您可以像这样获得在 SO 上花费的总时间:

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

我相信这会给你你正在寻找的结果,但需要注意的是,你必须根据你的需要(小时、分钟、秒、天等)放置度量单位。

于 2009-06-09T14:23:34.287 回答