Linq在一次迭代中选择和聚合

时间:2012-10-17 14:22:25

标签: c# linq aggregate

有没有办法在没有枚举fooCollection两次的情况下使用linq执行此操作?

var fooCollection = // get foo
var selectedIds = new List<int>();
var aggregateContent = String.Empty;

foreach (var f in foo)
{
    selectedIds.Add(foo.Id);
    aggregateContent += foo.Content
}

var results = new FooResults
{
    Content = aggregateContent,
    SelectedIds = selectedIds
};

return results;

5 个答案:

答案 0 :(得分:13)

是的,您可以使用Enumerable.Aggregate方法:

var result = fooCollection.Aggregate(new FooResult(),
                                    (r,f) => 
                                    { 
                                        r.SelectedIds.Add(f.Id);
                                        r.Content += f.Content;
                                        return r;
                                    });

这样可以避免副作用。我不喜欢LINQ中的副作用。 =)

答案 1 :(得分:2)

有一种可能性,但我认为这是一种黑客行为:

var aggregateContent = String.Empty;
var selectedIds = foo.Select(x => { aggregateContent += x.Content;
                                    return x.Id; })
                     .ToList();

我会选择你已经拥有的循环。它可以提供更清晰的任何LINQ解决方案。

答案 2 :(得分:1)

你可以这样做:

foo.ForEach(x => { selectedIds.Add(x.Id); aggregateContent += x.Content; });

我建议不要将内容连接成字符串,而是使用StringBuilder代替。

修改

如果您没有为ForEach实现IEnumerable的LINQ扩展库,可以使用以下方法:

public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action) 
{ 
    foreach(T item in enumeration) 
    { 
        action(item); 
    } 
} 

答案 3 :(得分:0)

您要求的是让Linq语句产生两个结果。 linq的整个想法是允许简洁的函数编程风格,没有副作用。

如果您想要多个结果和良好的性能,则不应使用Linq,并使用常规foreach。

答案 4 :(得分:0)

我也找不到它,所以我这样写自己的书

public static IEnumerable<V> SelectAggregate<T,V>(this IEnumerable<T> items,V seed,Func<V,T,V> func)
{
    foreach(var item in items)
    {
        seed    = func(seed,item);
        yield return seed;
    }
}


var array = new int[]{ 1,2,3 };
var sumArray = array.SelectAggregate(0,(seed,item) => seed + item).ToArray();
//// { 1,3,6 }