2009-10-02 75 views
23

我见过的.NET聚合函数的简单示例工作就像这样:LINQ的聚集体复合类型为字符串

string[] words = { "one", "two", "three" }; 
var res = words.Aggregate((current, next) => current + ", " + next); 
Console.WriteLine(res); 

怎么可能,如果你想聚合更多复杂“汇总”功能使用类型? 例如:有2种性能如“键”和“值”和在类所需的输出是这样的:

"MyAge: 33, MyHeight: 1.75, MyWeight:90" 

回答

40

有两个选项:

  1. 项目到string然后骨料:

    var values = new[] { 
        new { Key = "MyAge", Value = 33.0 }, 
        new { Key = "MyHeight", Value = 1.75 }, 
        new { Key = "MyWeight", Value = 90.0 } 
    }; 
    var res1 = values.Select(x => string.Format("{0}:{1}", x.Key, x.Value)) 
           .Aggregate((current, next) => current + ", " + next); 
    Console.WriteLine(res1); 
    

    这具有使用第一string元件作为种子的优势(没有前置的“,”),但会消耗更多的内存用于在此过程中创建的字符串。

  2. 使用接受种子的总超载,也许是StringBuilder

    var res2 = values.Aggregate(new StringBuilder(), 
        (current, next) => current.AppendFormat(", {0}:{1}", next.Key, next.Value), 
        sb => sb.Length > 2 ? sb.Remove(0, 2).ToString() : ""); 
    Console.WriteLine(res2); 
    

    第二委托转换我们的StringBuilderstring,使用条件修剪出发“”。

+0

完美的,就在我期待的位置,所以我可以从他们的时间开始计时,滚动自己的圈子更快(我的测试周期中只有1或2个项目) – Myster 2009-10-04 21:08:57

+0

列表中的项目很少,与更迫切的解决方案相比,为Select/Aggregate设置“额外”枚举器所带来的性能似乎相当严重。与大多数功能解决方案一样,问题在于性能/可读性折衷是否可以接受。鉴于不熟悉的Aggregate对于大多数人而言是多么的容易,很容易得出结论:在这种情况下,必要的解决方案是独立于性能的“更好”。 – dahlbyk 2009-10-05 01:32:50

+0

写完之后,我同意。 Aggregate是相当神秘的,但它是一个很好的工具,在我的箱子里;-) – Myster 2009-10-07 21:01:42

3

聚集函数接受一个代表参数。通过更改委托来定义所需的行为。

var res = data.Aggregate((current, next) => current + ", " + next.Key + ": " + next.Value); 
+6

如果您要聚合成源以外的类型,则需要指定种子。指定“”作为种子会编译,但结果将以“,”开头。 – dahlbyk 2009-10-02 11:28:41

4

聚合有3个重载,所以你可以使用不同类型的积累你正在枚举的项目。

您需要传入种子值(您的自定义类)以及添加合并种子和一个值的方法。例如:

MyObj[] vals = new [] { new MyObj(1,100), new MyObj(2,200), ... }; 
MySum result = vals.Aggregate<MyObj, MySum>(new MySum(), 
    (sum, val) => 
    { 
     sum.Sum1 += val.V1; 
     sum.Sum2 += val.V2; 
     return sum; 
    }