Weird Lambda behavior in string equality - c#

I have an array of strings obj[] values, but trying to use equality seems to be different than what I might expect, can someone clarify this?
content of values is ["train","train"];
var first = values.First();
values.Skip(1).All(v => Equals(v, first))
false
values.Skip(1).All(v => v.Equals(first))
true
Equals(values[0], values[1])
true
Equals(values[1], values[0])
true
values.Skip(1).All(v => Equals(v, first) == true)
false
values.Skip(1).Any(v => Equals(v, first) == false)
true
Any clue why it returns false?
Edit1: I have wrote a unit test and it passes, I'm checking if the strings have different cultures as #Michael Randall suggested
Equals implementation on MSDN

Your problem must be your input
Note : You should consider doing proper string comparison. Best Practices for Using Strings in .NET
However as you can see with the appropriate input, your code actually works
var first = "train";
var values = new object[]{"train", "train"};
Console.WriteLine(values.Skip(1).All(v => Equals(v, first)));
Console.WriteLine(values.Skip(1).All(v => v.Equals(first)));
Console.WriteLine(Equals(values[0], values[1]));
Console.WriteLine(Equals(values[1], values[0]));
Console.WriteLine(values.Skip(1).All(v => Equals(v, first) == true));
Console.WriteLine(values.Skip(1).Any(v => Equals(v, first) == false));
Output
True
True
True
True
True
False
You can test it here

#TheGeneral answer is usually the correct one, but in my case restarting the machine removed this issue. my guess it was the debugger have a bug.

Related

Inline IF with no ELSE

I'm trying to update the property of objects in a List based on a 0/1 pattern in a string.
//list.length is always == pattern.length
string pattern = Convert.ToString(8, 2);
var listWithDeleted = list.Select((s, index) => pattern[index] == '1' ? s.IsDeleted == true : s.IsDeleted = s.IsDeleted);
I'm a bit sad about the else-clause : s.IsDeleted = s.IsDeleted of my inlined if-statement. I understand inlined if needs an else-clause as it needs to return a value but it made me wonder if there may be a cleaner way to do this.
You can use:
s.IsDeleted = pattern[index] == '1' || s.IsDeleted
If it's already true, it will stay true regardless of pattern[index], otherwise it will only become true if pattern[index] is '1'
Here's another solution
s.IsDeleted = pattern[index] == '1' ? true : s.IsDeleted
Filter and only apply the operation where you need to. You wouldn't write the foreach equivalent in a ternary like that, so I don't see why you should do it that way in LINQ either.
list.Where((s, index) => pattern[index] == '1').Select(s => s.IsDeleted = true);
Note that it's strange to mutate in the Select (compounded by the strangeness of mutating in a ternary); in this case your listWithDeleted actually returns an IEnumerable<bool> (the result of the ternary) which seems odd. It would be better to use List.ForEach or your own void returning IEnumerable.ForEach extension to make intent a little clearer.

Why does this handle not all conditions?

I am reading the answer to this question: (Is there a better way of calling LINQ Any + NOT All?). Why does this handle not all conditions? Sorry for creating a new question, but I don't have enough reputation to add a comment on the original question.
var anyButNotAll = mySequence
.Select(item => item.SomeStatus == SomeConst)
.Distinct()
.Take(2)
.Count() == 2;
If the condition is always false (or always true) then when projecting the sequence using the condition and calling Distinct there will be 1 result, not two, so Count() == 2 will return false, not true.

Can I use the .Min() Linq extension method on a bool type?

I want to find if I have any bools that are false in a collection. Can I use the following code to find it?
this.MyList.Min(e => e.MyBool)
I'm hoping this will return false if there is a false in the collection.
You can use (renamed the collection for reasons of readability):
bool anyFalse = myBools.Any(b => !b);
or
bool anyFalse = !myBools.All(b => b);
both are efficient since they break on the first false.
If there are complex objects in the collection(as it seerms to be) use:
bool anyFalse = MyList.Any(x => !x.MyBool);
or
bool anyFalse = !MyList.All(x => x.MyBool);
Yes, it will work because Boolean is IComparable<Boolean> but it's awkward and thus it's harder to understand the intent of your code.
Additionally, your code will have to go through the whole sequence just to find out if there's a false, and it will throw if the sequence is empty.
Use All instead:
MyList.All(item => item.MyBool)
This will return false if there's any false value in the sequence. If the sequence is empty, All will return true.

Is there an opposite of LINQ's All method?

I'm currently using
a_list.All(item => !(item.field_is_true == true))
which works well, but I'd like to know if there was a proper LINQ method to do the opposite of all.
All() checks that a given Predicate returns true for all items. In terms of framework development, it wouldn't make any sense to write a seperate method that checks that a given Predicate returns false for all items, as it is so easy to "not" a predicate.
However, you can write your own extension method:
public static bool None<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return !source.Any(predicate);
}
The exact opposite of All() is essentially None, but since LINQ has no None() method, you can accomplish the same result through !set.Any().
!a_list.Any(item => item.matches == true)
This will produce true if none of the items in a_list have a matches value that is true.
Another example:
names.All(item => item.StartsWith("R"))
is true if all of the items in names start with R (as you know already).
!names.Any(item => item.StartsWith("R"))
is true if none of the items in names start with R.
Based on your comment below, it sounds like you might just be looking for a way to accomplish the same result as your current code snippet, but in a different way. This should provide the same result as your current code, but without the ! in the predicate:
!a_list.Any(item => item.matches == true)
This can be further simplified to:
!a_list.Any(item => item.matches)
I'd imagine yours could be simplified as well, to this:
a_list.All(item => !item.matches)
There's rarely a good reason to explicitly compare a boolean value with true or false.
you wrote:
a_list.All(item => !(item.field_is_true == true))
that is like doing:
a_list.All(item => item.flag== false) // more readable to me...
//return true if all of the items have a **flase** value on their flag
you can also use .any() to achieves the same result:
!a_list.Any(item => item.flag==true)
as for performence issues: .any() vs .all() - both would have identical performance
(when linq to object is used) , find more here : LINQ: Not Any vs All Don't
Rather than negate the All() condition, simply use the Any() with the same predicate and treat the returned boolean appropriately.
So, rather than:
bool conditionDoesntExist = a_list.All(item => !(item.field_is_true == true));
you can have
bool conditionDoesExist = a_list.Any(item => item.field_is_true == true)
Note the change in name of the flag. (Of course I'm overlooking semantic stuff like the original predicate could have been written as item => item.field_is_true == false or simply item => !item.field_is_true ).
If you want to keep the flag name the same then still use the Any() but negate it:
bool conditionDoesntExist = !a_list.Any(item => item.field_is_true == true);
All
a_list.All(item => item.condition)
Some
a_list.Any(item => item.condition)
Not all
!a_list.All(item => item.condition)
or:
a_list.Any(item => !(item.condition))
None
!a_list.Any(item => item.condition)
or
a_list.All(item => !(item.condition))

How to make AND operator in C# linq?

IEnumerable<WireUsrTgInfo> lstWireData =
(from var in lstWireUsrTgInfo
where var.bWireData == true && var.bWireData == false --> This is not working
select var).AsEnumerable<WireUsrTgInfo>();
How to do this ...
according to the code provided
var.bWireData == true && var.bWireData == false
it can not work, as the same variable can not contemporary be equal to both oposite values.
if you need parametrize this, you can do it like :
bool expectedValue = true; //OR False
IEnumerable<WireUsrTgInfo> lstWireData = (from var in lstWireUsrTgInfo
where var.bWireData == expectedValue
select var).AsEnumerable<WireUsrTgInfo>();
EDIT
And don't use var in the query, it's contextual (as mantioned by Monkieboy) C# keyword. To be clear: you can use it, but you have to avoid doing that as it creates confusion.
bWireData cannot both be true AND false. There's a flaw in your logic.
As other answers stated, your filter condition is wrong. But there is something else I want to add:
Don't compare boolean data with true or false. Boolean data is actually an answer to question is it true or not.
var query = from info in lstWireUsrTgInfo
where info.bWireData // selects data which is true
select info;
Also var is a keyword;
Also do not use prefixes in variable names (consider better naming instead - HasWireData, wireUserTagInfos).
This will never work: WHERE bWireData == true && bWireData == false is illogical be cause bWireData can't be both true and false at the same time.
var is a keyword and to avoid confusion should therefor not be used as a name for a variable.
&& is the correct operator. However, as other posters have noted, your query as it stands is equivalent to saying "Make me happy if Obama is president and Obama is not president". Basically you have set up a contradiction, which will always evaluate to false and thus return no results. As an aside, you may be interested to learn that && is a conditional-and, meaning that the second term is only evaluated if the first term is true, thus saving the processing of second term if the result is inevitably false anyway.

Categories