Ed Beaty
Ed Beaty

Reputation: 467

Linq: Exclude results using Zip

I have a list of bool, and a list of strings. I want to use IEnumerable.Zip to combine the lists, so if the value at each index of the first list is true, the result contains the corresponding item from the second list.

In other words:

 List<bool> listA = {true, false, true, false};
 List<string> listB = {"alpha", "beta", "gamma", "delta"};
 IEnumerable<string> result = listA.Zip(listB, [something]); 
 //result contains "alpha", "gamma"

The simplest solution I could come up with is:

 listA.Zip(listB, (a, b) => a ? b : null).Where(a => a != null);

...but I suspect there's a simpler way to do this. Is there?

Upvotes: 5

Views: 1033

Answers (4)

usr
usr

Reputation: 171178

I think this is simpler:

listA
 .Zip(listB, (a, b) => new { a, b } )
 .Where(pair => pair.a)
 .Select(pair => pair.b);

That logically separates the steps. First, combine the lists. Next, filter. No funky conditionals, just read it top to bottom and immediately get it.

You can even name it properly:

listA
 .Zip(listB, (shouldIncludeValue, value) => new { shouldIncludeValue, value } )
 .Where(pair => pair.shouldIncludeValue)
 .Select(pair => pair.value);

I love self-documenting, obvious code.

Upvotes: 10

Dave Zych
Dave Zych

Reputation: 21887

This is as short as I could get it:

var items = listB.Where((item, index) => listA[index]);

Where has an overload that provides the index. You can use that to pull the corresponding item in the bool list.

Upvotes: 4

Lee
Lee

Reputation: 144126

You don't need to use Zip if you can index into listA:

var res = listB.Where((a, idx) => listA[idx]);

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125620

listA.Zip(listB, (a, b) => new { a, b }).Where(x => x.a).Select(x => x.b);

It uses anonymous type to handle Zip method subresults.

Upvotes: 0

Related Questions