LINQ ternary result of binary list - c#

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?

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

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

Related

Null coalescing operator evaluation with and without parenthesis

I have a rule that runs against an object before an actual evaluation takes place. The rule checks that the collection is not null and that the elements have a valid id (greater than zero). When testing with a null collection this behaves as expected. However when testing with a non null collection with invalid arguments the evaluation does not behave as I expect. Without parenthesis the expression containing the null coalescing operator returns true but with parenthesis it returns the correct value. Trying to understand how this changes the evaluation of operations as I would imagine them to evaluate to the same result in both cases.
var testRule = new CollectionRule(null);
testRule.Verify();
//Verify => False
testRule.Verify2();
//Verify2 => False
testRule = new CollectionRule(new int[] { -1 });
testRule.Verify();
//Verify => True
testRule.Verify2();
//Verify2 => False
public class CollectionRule
{
private IEnumerable<int> _elements;
public CollectionRule(IEnumerable<int> elements) => _elements = elements;
public bool Verify()
{
bool result = _elements?.GetEnumerator().MoveNext() ?? false && _elements.All(i => i > 0);
System.Diagnostics.Debug.WriteLine($"Verify => {result}");
return result;
}
public bool Verify2()
{
bool result = (_elements?.GetEnumerator().MoveNext() ?? false) && _elements.All(i => i > 0);
System.Diagnostics.Debug.WriteLine($"Verify2 => {result}");
return result;
}
}
&& has a higher precedence than ??, so this:
a ?? b && c
will be evaluated like:
a ?? (b && c)
In your case b is false, and false && c is just false, so the whole thing simplifies down to a ?? false.

return statement that checks the first two characters before proceeding

return ship.DefenseType?.PropulsionMethod != null
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
Hi, my current return statement, above, is returning a Propulsion method if it's not null. However, my database has different types of
propulsion methods denoted by the first 2 letters in the field(PK, PA, PT, etc).
How can I check to make sure that the PropulsionMethod starts with "PK" before going further into the return statement?
In pseudo code, it might look something like this:
if (ship.DefenseType?.PropulsionMethod).startsWith("PK")
&& ship.DefenseType?.PropulsionMethod != null)
{
return new BattleMethod(ship.DefenseType.PropulsionMethod)
}
else
{
return null;
}
I tried
return ship.DefenseType?.PropulsionMethod != null &&
ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
But I get this error:
operator && cannot be applied to operands of type bool and bool?
Just add this condition too:
return ship.DefenseType?.PropulsionMethod != null
&& ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod) : null;
As the operator is && so the second condition will be evaluated if the first one was true (not null in this case).
You can compare nullable bool directly with true:
return ship.DefenseType?.PropulsionMethod?.StartsWith("PK") == true
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;

Better way to check three properties having some value or all of them are NULL in C#

There are three properties in the object
{obj.prop1, obj.prop2, obj.prop3} These properties are NULLABLE INTEGER
And I need to validate either all three properties should contain some value or all three properties are null.
Here's the validation
if (!((!obj.prop1.HasValue && !obj.prop2.HasValue && !obj.prop3.HasValue) ||
(obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue)))
{
//throw new Exception("");
}
Is there any better way to do it via some other Logical operators?
You can try this
if (obj.prop1.HasValue != obj.prop2.HasValue || obj.prop2.HasValue != obj.prop3.HasValue)
throw...
The expression above yields:
p1.HasValue p2.HasValue p3.HasValue
==========================================================================
false false false => false || false => false
false false true => false || true => true
false true false => true || true => true
true false false => true || false => true
false true true => true || false => true
true true false => false || true => true
true false true => true || true => true
true true true => false || false => false
You could use null coalescing for the null check, but you would still need to verify if all items do actually have a value for the other:
if((obj.prop1 ?? obj.prop2 ?? obj.prop3) == null
|| (obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue))
{
// conditional block
}
However, I think the original way you have it is more understandable to an average user.
I don't know of a logical operator that can make the code look nicer, but what I often do is wrap the functionality in to a method with a name that describes the test. This helps reduce the code size, and makes the code "self documenting".
Here's an example method that will test a bunch of objects to see if they are "partially null".
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
And this method in action: https://dotnetfiddle.net/6QIpDF
public class Program
{
public static void Main()
{
int? one = 1;
int? two = 1;
int? three = 1;
int? nullOne = null;
int? nullTwo = null;
int? nullThree = null;
Console.WriteLine(ArePartiallyNull(one, two, three));
Console.WriteLine(ArePartiallyNull(nullOne, nullTwo, nullThree));
Console.WriteLine(ArePartiallyNull(one, two, nullThree));
}
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
}
There are actually a handful of ways you can go about this depending on how "automatic" you want it to be when you add new properties for the object. If you don't mind updated your check each time you add a new property, I would just go with a simple method for comparison.
First, the example you have provided is a just fine approach. This is actually going to be the most performant way to perform the check. The downside is it is overly verbose, and doesn't scale well if you plan to add a lot more properties to the object.
The next method you could consider is to create a custom function that compares the properties for you. This way, when you use the function in your code, it is a bit less verbose. The function below will take as many int? variables you want to throw at it, and verify that they all either have a value, or don't have a value.
bool Test(params int?[] props)
{
bool? lastValue = null;
foreach(int? p in props)
{
// We haven't got a status yet so we just use the status for the first prop
if (lastValue.HasValue == false)
lastValue = p.HasValue;
else
{
// If the status of this next prop doesn't match the first, we know it is false
if (p.HasValue != lastValue.Value)
return false;
}
}
// Default back to true since we didn't identify any issues.
return true;
}
The last option I would propose would be to use reflection. With reflection, you could loop over the properties and check each one using similar logic to the function above. The benefit of this approach is that you do not need to adjust your logic as you add new properties. The downside is performance.
If you just want to make sure that all three have a value or don't have a value (regardless of what the value is) then
bool AllAreTrueOrFalse(params bool[] values)
{
return values.All(value=>value) || !values.Any(value=>value);
}
var allTrueOrFalse = AllAreTrueOrFalse(obj.prop1.HasValue, obj.prop2.HasValue,
obj.prop3.HasValue);

How to deal with null linq query result?

I have a linq query in which i am getting the user list and after that we are getting the record by userid filter.
var user = UserDal.GetAllUsers().First(n => n.UsersID == 1);
But what should do if GetAllUsers() function returns null ? Should we check it by applying Any() ? Or something else ?
But what should do if GetAllUsers() function returns null ?
If UserDal.GetAllUsers returns null, then you can't use Any, you will have to check it against null. You can only use Any or FirstOrDefault if the method returns a collection (even empty).
If the method could return null then:
var temp = UserDal.GetAllUsers();
if(temp != null)
{
var user = temp.FirstOrDefault(n=> n.UserID == 1);
}
If your method could return an empty collection instead of null then you can do:
var user = UserDal.GetAllUsers().FirstOrDefault(n => n.UsersID == 1);
You should modify your method UserDal.GetAllUsers to not return a null. If there are no records then an empty collection should be returned.
Why not simply check if it is null?
var users = UserDal.GetAllUsers();
if (users == null || !users.Any())
{
// handle error
}
var user = users.First(x => x.Id == someId);
However, if you're in control of the code-base, I'd certainly say that you should make it so GetAllUsers never returns null.
You could use [DefaultIfEmpty] and use that instance as default value: to handle null value
You could use Monads, e.g. https://github.com/sergun/monads.net
Or you could implement your own extension methods.
This code is adapted from the original extension method and returns default(T) instead of throwing an exception.
// UserDal.GetAllUsers() returns null and user is null
var user = UserDal.GetAllUsers().MyFirstOrDefault(n => n.UsersID == 1);
public static class IEnumerableExtensions
{
public static T MyFirstOrDefault<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
if (source == null) return default(T);
if (predicate == null) return default(T);
foreach (T element in source)
{
if (predicate(element)) return element;
}
return default(T);
}
}
Or you could use null checks or ensure never to return null to safeguard against null reference exception when using the standard extension methods.

FindAll multiple conditions

So I'm trying to use FindAll to return a list of objects that match. It works great when I only use one condition, for example
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
return p1.WL_ID == patlist[i].wl_id;
});
But I would like to use multiple conditions, some of which contain if statements and I can't figure out how. It seems like the format needs to have a return statement, and the example from Microsoft (http://msdn.microsoft.com/en-us/library/fh1w7y8z.aspx) only uses one condition.
I could either have multiple FindAll methods for each condition, or just make a loop that scans through all the values myself, but there's got to be an obvious thing I'm missing, right?
I'm not quite sure what "if loops" are, but you can always just stitch them together:
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
if(p1.WL_ID != patlist[i].wl_id)
return false;
if(otherStuff != 5)
return false;
for(var x in p1.stuff)
if(x == 7)
return false;
return true;
});
Try the following:
var patientStatus = statusList.Where(p => p
{
// Put in logic here as you need
return p.WL_ID == patlist[i].wl_id || p.YourSecondProperty == WhateverYouWantToCheck;
}
You can think about something like
public abstract class Condition
{
public abstract bool Sutisfied(StatusReader.onestatus status);
}
public class Condition1 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
public class Condition2 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
After can have a list of conditions, like
List<Condition> conditions =
new List<Condition>{new Conditon1(), new Condition2()}
and after this list use inside
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus status)
{
return conditions.TrueForAll(c=>c.Sutisfied(status));
});
Your delegate simply needs to return true for a match to your conditions and false for a non-match to your conditions. It doesn't have to be a single line return statement. You can create boolean values, have if statements, for loops, and anything else you want in your delegate - so long as it returns true or false along all code paths.
So you can do as many if statements or loops as you want.
If you really want to maintain it as one line, you can do something like the following...
return (condition1 == condition1) || (condition2 == condition2) || (condition3 == condition3);

Categories