Mike-Kilo
Mike-Kilo

Reputation: 1312

LINQ ternary result of binary list

Assume I have a list of binary parameters (in reality it is a list of checkboxes' IsChecked.Value property). I'm trying to get the bool? (ternary) result that:

Until now I came up with the solution that requires iterating over the list twice (checking whether all elements are either true or false) and then comparing the results to deciding whether to return true, false or null.

This is my code:

bool checkTrue = myListOfBooleans.All(l => l);
bool checkFalse = myListOfBooleans.All(l => !l);
bool? result = (!checkTrue && !checkFalse) ? null : (bool?)checkTrue;

How can I achieve it in only one iteration over the list?

Upvotes: 1

Views: 87

Answers (2)

juharr
juharr

Reputation: 32296

You could do that by using Aggegrate

public bool? AllSameValue(List<bool> myListOfBooleans)
{
    if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense

    return myListOfBooleans.Cast<bool?>().Aggregate((c, a) => c == a ? a : null);
}

That casts your values to bool? so that you can then compare them and return the value if that they all match or null if there is a difference.

Of course you could exit early by taking the first one and using All to see if the rest match or not.

public bool? AllSameValue(List<bool> myListOfBooleans)
{
    if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense

    bool first = myListOfBooleans[0];
    return myListOfBooleans.All(x => x == first ) ? first : null;
}

Upvotes: 2

Ren&#233; Vogt
Ren&#233; Vogt

Reputation: 43906

You can simply count the true values:

int c = myListOfBooleans.Count(l => l);
bool? result = c == myListOfBooleans.Count 
               ? (bool?)true 
               : (c == 0 ? (bool?)false : null);

Note that this is true for an empty list, you may want to tweak that according to your required logic.


For a better performance (though I don't think it matters in a UI context) you could write an extension that could even return early if the result is clear (instead of iterating through the whole list):

public static bool? AllOrNothing(this IEnumerable<bool> list)
{
    if (list == null) throw new ArgumentNullException(nameof(list));

    using(var enumerator = list.GetEnumerator())
    {
        if (!enumerator.MoveNext()) 
            return null; // or true or false, what you need for an empty list

        bool? current = enumerator.Current;
        while(enumerator.MoveNext())
            if (current != enumerator.Current) return null;
        return current;
    }
}

And use it:

bool? result = myListOfBooleans.AllOrNothing();

Upvotes: 2

Related Questions