Reputation: 6588
Is there a way to do this with linq without enumerating the fooCollection
twice?
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;
Upvotes: 10
Views: 17766
Reputation: 1512
I can't find it too so I write my own like this
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 }
Upvotes: 0
Reputation: 25573
Yes, you can use the Enumerable.Aggregate method:
var result = fooCollection.Aggregate(new FooResult(),
(r,f) =>
{
r.SelectedIds.Add(f.Id);
r.Content += f.Content;
return r;
});
This has the benefit of being side-effect free. I dislike side effects in my LINQ. =)
Upvotes: 18
Reputation: 33139
You could do this:
foo.ForEach(x => { selectedIds.Add(x.Id); aggregateContent += x.Content; });
I would recommend not concatenating the Content into a string, but to use a StringBuilder
instead.
EDIT
If you don't have a LINQ extension library that implements ForEach
for IEnumerable
, here is a method you can use:
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach(T item in enumeration)
{
action(item);
}
}
Upvotes: 1
Reputation:
What you are asking for is to have a Linq statement produce two results. The whole idea of linq is to allow a concise functional programming style without side effects.
If you want multiple results and good performance, you should not be using Linq, and use a regular foreach.
Upvotes: 0
Reputation: 174349
There is one possiblity, but I consider it a hack:
var aggregateContent = String.Empty;
var selectedIds = foo.Select(x => { aggregateContent += x.Content;
return x.Id; })
.ToList();
I would go with the loop you already have. It is much cleaner as any LINQ solution you could come up with.
Upvotes: 2