LINQ ternary result of binary list

时光总嘲笑我的痴心妄想 提交于 2021-01-28 07:47:56

问题


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:

  • is true if all the elements in the list are true
  • is false if all the elements in the list are false
  • is null in all other cases, thus there are both true and false elements in the list or the list is empty

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?


回答1:


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;
}



回答2:


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


来源:https://stackoverflow.com/questions/57695722/linq-ternary-result-of-binary-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!