Why does this handle not all conditions? - c#

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.

Related

How to search from top xxx rows in database using Entity Framework

I have a database with over 1 million records, I want to find a value in this database, but I know that this value is found somewhere in the top 1000 records.
List<string> onHoldOrderslist =
orderList.Where(m => (m.customerId == item.customerId)
&& (m.Marketplace == Market.US)
&& (m.OrderStatus == "onHold"))
.Select(s => s.OrderId)
.ToList();
In the code, I do not want to search the whole orderList database table, just the top xxx records.
My questions are:
How is it done with linq? I couldn't find any example!
Does it enhance the query performance?
Use
List<string> onHoldOrderslist = orderList.Where(m => (m.customerId == item.customerId) && (m.Marketplace == Market.US) && (m.OrderStatus == "onHold"))
.OrderBy(x => x.WhateverMakesSense)
.Take(1000)
.Select(s => s.OrderId)
.ToList();
Please note that ordering is important as otherwise you may get random 1000 elements...
Given you say this is "a record" and you are only returning one, don't worry about the fact that it's in the top 1000 (and top doesn't even mean anything unless you specify an order). Using Take(1000) after the where clause will do nothing as there is only one record anyway. All you need is an index, in this case on customerId, Marketplace, and OrderStatus.

LINQ query for finding one item in list AND verifying list does not contain another item

So far I have come up with this:
list.Any(s => s.EnumIdValue == Close) && !list.Any(s => s.EnumIdValue == Reset || s.EnumIdValue == Cancel);
EnumIdValue contains several different possible values like Close, Reset, Cancel, SomeOtherState, etc. There should never be duplicates but it's still possible.
This does exactly what I want. But would there be a better (shorter) way to write this query?
Your original is fine. The other variant that would work is this:
var newQuery =
list.Any(s => s.EnumIdValue == EnumIdValue.Close) &&
list.All(s => s.EnumIdValue != EnumIdValue.Reset &&
s.EnumIdValue != EnumIdValue.Cancel);
In English: does the list have at least one Close and is every item in the list not Reset and not Cancel?
By the way, sometimes formatting your code nicely makes a big difference in terms of readability.
The answer is: There is no better way to write it.
If you try to write it in one lambda, you can think of the s as a single item in the list. If the item is a Close, it will of course not be something else so it's useless to check for that in the same lambda. If you want to check if the list doesn't contain some other values, you're forced to do it with another expression.
You can use a HashSet to test if the collection contains at least 1 of each EnumIdValue:
var enumIds = list.Select(s => s.EnumIdValue).ToHashSet();
return enumIds.Contains(Close) && !(enumIds.Contains(Cancel) || enumIds.Contains(Reset));
// or
return enumIds
.Intersect(new[] { Cancel, Reset, Close })
.SequenceEqual(new [] { Close });
// or (throws exception)
enumIds.IntersectWith(new[] { Cancel, Reset, Close })
return enumIds.Single() == Close;
This would be useful if you need to do different types of checks based on whether or not enumIds contains Close.
How about
var items = list.Select(s => s.EnumIdValue == Close)
if(items.Count==1)
{
//todo
}
Here's a fairly readable alternative:
var opts = new [] { Close, Reset, Cancel };
var desired = new [] { Close };
return list
.Select(s => s.EnumIdValue)
.Distinct()
.Where(opts.Contains)
.SequenceEqual(desired);

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.

When to check List<T> for null, when for 0 and when both

I use ADO.NET entity framework and very often there are code snippets like this :
List<Sole> entity = soleService.All()
.Where(s => (s.ShoeLastID == shoeLastID) && (s.Status == 20))
.ToList();
Since now I haven't think much about it and just made this check:
if (entity.Count > 0)
believing that it is enough. Now I see that many people check with Any() and for null. How to be sure at a certain situation what kind of checks I need and in this certain scenario which as I said - I use very often is if (entity.Count > 0) enough?
if (entity.Count > 0) or if (entity.Any()) are identical in you case. As you already fetched all the data from the DB, the list has been built and you knows its size. So .Count property doesn't iterate over anything.
In the other hand, do not call the .Count() IEnumerable extension if you didn't fetched all data, because it'll enumerate items for nothing.
Use instead:
bool test = soleService.All()
.Any(s => (s.ShoeLastID == shoeLastID) && (s.Status == 20));
if (test)
{
...
}
Also, LINQ extensions won't return null but an empty IEnumerable, so don't check for null.
If you have a .ToList() call, then the list is always a list. Maybe empty, but never null.
The check for .Any() instead of .Count() > 0 is a performance improvement for most containers or enumerables because .Any() will only touch the first element if there is one. .Count() would need to count through your container to the end although you are not interested in the result, only in the fact that it's not zero.
Depends on what you need.
If you just want to know if any of entities match your predicate then use Any(), as it will return immediately upon finding the first matching entity.
Count() / Count will need to process all the entities which will typically be much slower.
Also prefer Linq's Count() to List Count as it doesn't have to create the full list in the memory, which can be very expensive with large result sets.
Any() will provide better solution cause it stopse after first matching.
in addition
I would suggest also to do ToList() only if Any() is true.
Youll save (micro) performance.
var t = soleService.All() .Where(s => (s.ShoeLastID == shoeLastID) && (s.Status == 20));
if (t.Any()) entity =t.ToList();
When you call if (entity.Count > 0) but entity == null, you will get an exception because .Count does not exist while entity is not initialized.
Of course a list can be null or empty. If you attempt to create a List<Sole> using LINQ as above and the soleService could be null, in which case you will get a NullReferenceException. So I would check that the soleService is not null or empty first. So
List<Sole> entity = null;
// ...
if (soleService != null && soleService.Count > 0)
entity = soleService.All()
.Where(s => (s.ShoeLastID == shoeLastID) && (s.Status == 20))
.ToList();
I hope this helps.
entity.Any() - will return true if there is any entities in your collection. entities.Count() == 0 will do the same. But I would recommend to use any because it will work faster. Because Count will return the amount of data in the collection, but any will trigger on the first item found in your collection.
But if you are not sure that your collection is initialized I would recommend you to use next construction:
if(entity!=null && entity.Any())
{
//Do something. You will get her always without error, And you will be 100% sure that your collection is not empty and it is initialized
}
Hope it helps.
entity.Any() is better choice. And you don't need to invoke .ToList() since this wll take all the data from the database and then just check its count.

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

Categories