1

I have a collection with objects in it, one of these objects attribute is a PublishRequestStatus, which is an enum value.

I'm recieving another list of all enum values that it needs to match, now I know how to search for 1 attribute matching a value:

model = model.Where(x => x.PublishRequestStatus == PublishRequestStatus.Denied);

But I'm having trouble matching all possible values from another collection. For example if I have a collection with PublishRequestStatus.Approved and PublishRequestStatus.Denied, how would I use LINQ to search for all objects with either of those enum values?

The only thing that I found what works is to make one list for each enum value in the 2nd collection in a loop, and at the end join all the lists together. However, I'm pretty sure that LINQ has a better way of doing what I'm trying to achieve.

anthonytimmers
  • 258
  • 1
  • 8

3 Answers3

3

This might not be exactly what you're looking for, but more of a suggestion. Instead of receiving a List<SomeEnum>, you can simply use bitwise | on your enum values, and look them up using Enum.HasFlags:

var flags = PublishRequestStatus.Approved | PublishRequestStatus.Denied;
var otherFlags = PublishRequestStatus.Approved | 
                 PublishRequestStatus.Denied | 
                 PublishRequestStatus.MaybeApproved;

Console.WriteLine(otherFlags.HasFlags(flags)); // Yields true.

Assuming such a thing is possible.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • I had a look at using bitflags cause of this question http://stackoverflow.com/questions/4194333/mvc-2-passing-enum-to-checkboxfor, however I'd have to change a lot of an existing system. I'll see if it's worth the change and it'll work in my context. – anthonytimmers Sep 21 '15 at 11:07
  • @anthonytimmers Good luck :). It would definitely save you unnecessary iterations. – Yuval Itzchakov Sep 21 '15 at 11:09
2

Something like this:

model = model.Where(x => myEnumList.Contains(x.PublishRequestStatus));

Alternativly with .Any():

model = model.Where(x => myEnumList.Any(y => y == x.PublishRequestStatus));

EDIT: According to Yuvals answer you may also simply check if your current element x has any of the flags:

model = model.Where(x => x.PublishRequestStatus.HasFlags(otherFlags));

This assumes your enum looks similar to this:

[Flags]
enum MyEnum { ... }

Which will allow bitwise |.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
1

The best from performance point of view is to avoid lambdas that introduce closure. So if you have

ICollection<PublishRequestStatus> filter = ...;

where filter could be List<PublishRequestStatus>, PublishRequestStatus[] or better HashSet<PublishRequestStatus>.

Then you can use method group predicate:

model = model.Where(filter.Contains);
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • The filter is a PublishRequestStatus[]. I don't know what you mean with introduces closure, but I'll have to read up in my free time on what exactly closure means in terms of coding. Model is of type GamePublishRequestViewModel[]. The status in this model is located at Model.PublishRequest.PublishRequestStatus, so I think lambda is necessary (?) and `model.Where(filter.Contains)` won't work. – anthonytimmers Sep 21 '15 at 14:13
  • 1
    Every `T[]` is also implementing a lot of interfaces, including `ICollection`. So if you have a variable `filter` of type `PublishRequestStatus>[]`, try the following `ICollection c = filter;` and will see that it will compile w/o errors. To apply it to my answer, just use `model.Where(((ICollection)filter).Contains)`. – Ivan Stoev Sep 21 '15 at 14:46
  • 1
    What about closures, it's good to know and there are a lot of sources, including SO with good explanation, but shortly it is a compiler generated class that is instantiated and holds some of your local variables as fields to make lambda that needs them working. See this for example http://stackoverflow.com/questions/32425833/why-does-c-sharp-compiler-create-private-displayclass-when-using-linq-method-any – Ivan Stoev Sep 21 '15 at 14:47