I have a series of lists:
List<foo> spamSpamAndSpam;
List<foo> spamSpamSpamSausageEggsAndSpam;
List<foo> spamSpamSpamSausageEggsBaconAndSpam;
List<foo> spamSpamSpamSpamSpamWithoutSpam;
List<foo> spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam;
I also have a series of values I'm looking for in a property of foo
:
List<string> Brian= new List<string>();
Brian.Add("Always");
Brian.Add("Look");
Brian.Add("On");
Brian.Add("The");
Brian.Add("Bright");
Brian.Add("Side");
Brian.Add("Of");
Brian.Add("Life");
I'm catching the references to all the foo
'ses in which a a given property (say, bar
) has a value contained in latter list. I'm doing it like this:
func<foo, bool> deadParrot = x => Brian.Contains(x.bar);
IEnumerable<foo> okLumberjacks = spamSpamAndSpam.Where(deadParrot);
okLumberjacks = okLumberjacks.Concat(
spamSpamSpamSpamSausageEggsAndSpam.Where(deadParrot));
// And so on, concatenating the results of Where() from every list of <foo>.
I need every foo
that has matched the filtering function in a single IEnumerable<foo>
so that I can call a method in all of them in one go, like this:
foreach (foo incontinentRunner in okLumberjacks)
{
incontinentRunner.SillyWalk();
}
So my question is... Is there a way to gather every foo
in a single collection without having to resort to something like:
ni = ni.Concat(someList.Where(filter));
I mean, is there some more elegant way to do something like this with Linq? I'm looking for something like:
okLumberjacks = spamSpamAndSpam.
And(spamSpamSpamSausageEggsAndSpam).
And(spamSpamSpamSausageEggsBaconAndSpam) /* etc */ .Where(deadParrot);
Or even better:
okLumberjacks = spanishInquisition.Where(deadParrot);
// Where the type of spanishInquisition is List<List<foo>>.
I don't want to modify the original lists of foo
because I need them as they are for another operation later on in the code.
Create a list of lists, and then just flatten it:
List<List<foo>> lists = new List<List<foo>>()
{
spamSpamAndSpam,
spamSpamSpamSausageEggsAndSpam,
//etc.
};
IEnumerable<foo> items = lists.SelectMany(item => item);
//do stuff with items.
Best I can think of would be something like:
var everything = spam1.Concat(spam2).Concat(spam3);
var itemsIWant = everything.Where(x => Brian.Contains(x));
Does Union() resolve your problem?
List<foo> spamSpamAndSpam;
List<foo> spamSpamSpamSausageEggsAndSpam;
List<foo> spamSpamSpamSausageEggsBaconAndSpam;
List<foo> spamSpamSpamSpamSpamWithoutSpam;
List<foo> spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam;
var x = spamSpamAndSpam
.Union(spamSpamSpamSausageEggsAndSpam)
.Union(spamSpamSpamSausageEggsBaconAndSpam)
.Union(spamSpamSpamSausageEggsBaconAndSpam)
.Union(spamSpamSpamSpamSpamWithoutSpam)
.Union(spamSpamSpamSpamSpamSpamSpamSpamSpamLovelySpamWonderfulSpam)
.Where(x => ..... );
NOTE: as it was properly noted, Union excludes duplicates from the return set. This is different behavior to the Concat method, which returns all the elements in the input sequences including duplicates. Since duplicate exclusion was not a requirement, Concat is probably better
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With