Home > Software design >  Linq where clause based on different bool condition C#
Linq where clause based on different bool condition C#

Time:09-14

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?

CodePudding user response:

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.

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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();

CodePudding user response:

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.

  • Related