简体   繁体   中英

Linq where clause based on different bool condition C#

Hi i'm trying to filter a list of items based on multiple bool parameters. I have 3 bool parameters (they are 3 checkbox in the UI): IsTypeA , IsTypeB , IsTypeC . Based on this 3 values i have to filter my list on a enum property of the items (called simply "Type"). Multiple checkbox can be checked. There's also another filter ("in", "out") above the type filter, but that is working. What i've tried so far is this:

FilteredDashboardItems = AllItems?.Where(x => 
                    Destination == "in" ?
                    (
                        (IsTypeA == true ? x.Type == Helpers.Enum.A : true)                    
                        &&
                        (IsTypeB == true ? x.Type == Helpers.Enum.B : true)                    
                        &&
                        (IsTypeC == true ? x.Type == Helpers.Enum.C : true)                    
                    ) : 
                    Destination == "out" ?
                    (
                        (IsTypeA == true ? x.Type == Helpers.Enum.A : true)                    
                        &&
                        (IsTypeB == true ? x.Type == Helpers.Enum.B : true)                    
                        &&
                        (IsTypeC == true ? x.Type == Helpers.Enum.C : true)                    
                    ) : true)?.ToList();

Problem is: if i singularly check a checkbox (let's say IsTypeA), the list gets correctly filtered for A Type items. But if i check another checkbox (let's say IsTypeB) instead of showing me A + B types filtered list, the list returns 0 items. How can i solve that?

You are using && And that will give you an Intersection of the both filter hence the 0 records.

You need to use OR || so that it shows element that satisfy either of the the filter.

Your condition is little bit weird

IsTypeA == true ? x.Type == Helpers.Enum.A : true

If IsTypeA is not nullable bool , then no need to compare it with true , because logically you get true == true or false == true , so you can just leave IsTypeA .

I would rewrite your condition:

FilteredDashboardItems = AllItems?.Where(x => 
                    Destination == "in" ?
                    (
                        (IsTypeA && x.Type == Helpers.Enum.A)                    
                        ||
                        (IsTypeB && x.Type == Helpers.Enum.B)                    
                        ||
                        (IsTypeC && x.Type == Helpers.Enum.C)                    
                    ) : 
                    Destination == "out" ?
                    (
                        (IsTypeA && x.Type == Helpers.Enum.A)                    
                        ||
                        (IsTypeB && x.Type == Helpers.Enum.B)                    
                        ||
                        (IsTypeC && x.Type == Helpers.Enum.C)                    
                    ) : true)?.ToList();

Now we have simple logic: if at least on of the selected types is equal to object type then keep this object

You need to use || instead of && but you can also simplify it a lot:

var typeFilters = new List<EnumType>(); // replace EnumType with the real type of the enum
if(IsTypeA) typeFilters.Add(Helpers.Enum.A);
if(IsTypeB) typeFilters.Add(Helpers.Enum.B);
if(IsTypeC) typeFilters.Add(Helpers.Enum.C);

FilteredDashboardItems = AllItems
    .Where(x => typeFilters.Contains(x.Type))
    .ToList();

You would need something like this:

    List<int> typesToCheck = new List<int>();

    if (IsTypeA) typesToCheck.Add((int)Helpers.A);
    if (IsTypeB) typesToCheck.Add((int)Helpers.B);
    if (IsTypeC) typesToCheck.Add((int)Helpers.C);

    FilteredDashboardItems = AllItems?.Where(x => Destination == "in" ?
        (IsTypeA || IsTypeB || IsTypeC ? typesToCheck.Contains(x.Type) : true)
        :
        Destination == "out" ?
            (IsTypeA || IsTypeB || IsTypeC ? typesToCheck.Contains(x.Type) : true)
            : 
            true)?.ToList();

And once you get it to this form, I'm sure you can also simplify the Destination conditions

In this type of question, In case the list has a lot of items, I will recommend to write Linq As QUERY, and not as Method.

(from item in AllItems
let firstCondition =  (IsTypeA && x.Type == Helpers.Enum.A) 
let secCondition =  (IsTypeB && x.Type == Helpers.Enum.B)
where firstCondition && secCondition
select item)?.ToList();

when you write in that form you create tmp Variable in the let section and save Time, more than that I believe that form is more readable in complex logics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM