I have a list of integers as below
List<int> myCollection = new List<int> { 2625 };
I am checking below condition
if(myCollection.Count() == 1 && myCollection.Any(number=> number == 2625))
{
// Do something
}
How can I optimize my query so that I can include both conditions single query?
Note: MyCollection may contain multiple elements hence I have used Any().
One obvious optimization would be to use List instance properties:
if(myCollection.Count == 1 && myCollection[0] == 2625))
{
// Do something
}
Actually, here you have one query. Not two. Since your collection is a list, Count() will be resolved to Count property of list. That being said, nothing actually will happen here
myCollection.Count() == 1
except from getting the value of Count.
The only query happens here
myCollection.Any(number=> number == 2625)
Furthermore, since the first condition you check if the Count is 1, if it doesn't, then Any wouldn't be evaluated at all. (This happens because we make use of &&).
I'm not sure why you want to
Optimize this, but if there is a single element why use .Any().
You could simply do
if(myCollection.Count() == 1 && myCollection.Single() == 2625)
{
// Do something
}
Related
When the linq query condition is not met, I'd expect a null to be returned from questions.FirstOrDefault() - but instead, an exception
Sequence contains no matching element
is thrown. Any ideas why?
var firstQ = questions.FirstOrDefault(a =>
a.Answers.Single(x => x.CourseAssignmentId ==
courseAssignmentId)?.Score == null) ?? questions.FirstOrDefault();
That's the difference between Single and SingleOrDefault.
Single throws an exception if there's any number of items different than 1 that match your predicate.
You should be using FirstOrDefault() instead. BTW you can combine the condition probably like
a.Answers.Single(x => x.CourseAssignmentId == courseAssignmentId && x.Score == null)
As others have already mentioned, it's the expected behavior of Enumerable.Single.
Anyway, it looks like an XY problem. Probably you should store the last scored question somewhere (e.g a dictionary).
That is, you could refactor your code as follows:
var assignmentScoredQuestionMap = new Dictionary<int, Question>();
// Fill the whole dictionary:
// You need to add for which assignment identifier you've answered a question
int assignmentId = 384;
// If the whole assignment exists, you set lastScoredQuestion, otherwise
// you set it to first question.
if(!assignmentScoredQuestionMap.TryGetValue(assignmentId, out var lastScoredQuestion))
lastScoredQuestion = questions.FirstOrDefault();
How do you index an IQueryable?
I am using a LINQ to sql query to get in values from a particular column. The query is as follows,
var intitalQuery = (from a in sql.GetTable<Staff_Time_TBL>()
where a.Info_Data == SelectedOption
select a.Staff_No).Distinct();
From there I want to be able index the intitalQuery variable and get values as needed.
That value is then used in another query.
My first try was this,
Column1.DataContext = sql.Staff_Time_TBLs.Where(item =>
item.Section_Data == SelectedOption &&
item.Staff_No == intitalQuery[0];
Then I tried this from here with no luck.
Column1.DataContext = sql.Staff_Time_TBLs.Where(item =>
item.Section_Data == SelectedOption &&
item.Staff_No == intitalQuery.First());
From what I can from the link is that that way gets just the first value, I want to be able to get all values via indexing. How do you go about that?
IQueryable<T> inherits from IEnumerable and as such has a wealth of extension methods to accomplish almost anything you'd need from a sequence. In particular, .ToList() turns an enumerable into a List<T> that allows efficient indexing.
.ToList() is slightly more efficient than the more obvious .ToArray() when working with sequences of unknown initial length, because .ToArray() requires an additional copy to end up with an array of exactly the right size. (But arrays are faster to loop over, so it all depends on what you're doing.)
You can do this:
public static List<Staff_Time_TBLs> GetIndexed(string staffNo){
var stuff = sql.Staff_Time_TBLs.Where(item =>
item.Section_Data == SelectedOption &&
item.Staff_No == staffNo;
return stuff.ToList();
}
//to use it...
initialQuery.ForEach(p=>{
var indexvalue = GetIndexed(p)
});
The following code shows how I am assigning data into IEnumerable<UnCompletedJobDetailsBO>.
There is a list (IEnumerable<UnCompletedJobDetailsBO>) that has another list (List<JobDetailsBO>), with that child list (List<JobDetailsBO>) having a list on it. But the AllocationDetailList only ever has one list item.
public IEnumerable<UnCompletedJobDetailsBO> GetControlDetails(DateTime startDate)
{
var controlDetails =
(from booking in db.BookingDetail
where booking.BookingDateTime >= startDate
orderby booking.DocketNo
select new UnCompletedJobDetailsBO()
{
CustomerName = booking.Customer.Name,
CompanyName = booking.CompanyDetail.Name,
JobList =
(from job in db.BookingJob.Where(x => x.BookingID == booking.BookingID) //get job list
select new JobDetailsBO()
{
JobID = job.JobID,
JobType = job.JobType,
ItemName = job.ItemName,
AllocationDetailList =
(from jobAllocationDetail in db.JobAllocation
join returnUnCollected in db.JobReturnUnCollected
on jobAllocationDetail.JobAllocationDetailID
equals returnUnCollected.JobAllocationDetailID
into returnJob
from returnUnCollected in returnJob.DefaultIfEmpty()
where (jobAllocationDetail.Booking.BookingID == booking.BookingID)
select new AllocationBO()
{
JobUnCollectedID = returnJob.JobUnCollectedID,
JobType = jobAllocationDetail.JobType,
CurrentStatus = jobAllocationDetail.CurrentStatus,
}).DefaultIfEmpty().ToList(),
}).DefaultIfEmpty().ToList(),
}).ToList();
return controlDetails;
}
I want to remove the JobList item if the inner list (AllocationDetailList) item satisfies the condition below. Sometimes AllocationDetailList may be null, so I check that also. But when I write below query, it does not remove that particular JobList item that satisfies the condition. Thanks in advance.
public List<UnCompletedJobDetailsBO> RemovePODFromSelectedList(
List<UnCompletedJobDetailsBO> unCompletedJobDetailsBO)
{
unCompletedJobDetailsBO
.SelectMany(y => y.JobList)
.ToList()
.RemoveAll(x => ((x.AllocationDetailList[0] != null) ?
x.AllocationDetailList[0].JobType == "D" &&
x.AllocationDetailList[0].JobUnCollectedID == null &&
x.AllocationDetailList[0].CurrentStatus == 5 :
x.AllocationDetailList.Count > 1));
return unCompletedJobDetailsBO;
}
Without a good, minimal, complete code example, I'm not sure that any performance concern can be addressed. It's hard enough to fully understand the question as it is, but without being able to actually test the code, to reproduce and observe a specific performance concern, it's hard to know for sure where your concern specifically lies, never mind how to fix it.
That said, from the code you posted, it is clear why items are not being removed from the list. The basic issue is that while the SelectMany() method does have the effect of allowing you to enumerate all of the elements from all of the different JobList objects as a single enumeration, the elements are enumerated as a new enumeration.
When you call ToList(), you are creating a whole new list from that new enumeration, and when you call RemoveAll(), you are only removing elements from that new list, not the lists from which they originally came.
You say you can get it to work with a for loop. I assume you mean something like this:
public List<UnCompletedJobDetailsBO> RemovePODFromSelectedList(
List<UnCompletedJobDetailsBO> unCompletedJobDetailsBO)
{
foreach (var item in unCompletedJobDetailsBO)
{
item.JobList.RemoveAll(x => ((x.AllocationDetailList[0] != null) ?
x.AllocationDetailList[0].JobType == "D" &&
x.AllocationDetailList[0].JobUnCollectedID == null &&
x.AllocationDetailList[0].CurrentStatus == 5 :
x.AllocationDetailList.Count > 1));
}
return unCompletedJobDetailsBO;
}
Note: there is no need to return unCompletedJobDetailsBO. That entire object is unchanged, never mind the variable. The only thing the code is modifying is each individual JobList object within the passed-in object's members. I.e. the above method could actually have a return type of void, and the return statement could be removed entirely.
It is possible you could speed the code up by removing the elements in a different way. The List<T>.RemoveAll() method is in fact reasonably efficient, with O(n) cost. But it still involves copying all of the data in the list after the first element that is removed (so that all the elements are shifted down in the list). If you have to have the list ordered, this may be as good as you can do, but if not, you could process the removal differently, or use a different data structure altogether, something unordered where removal of one or more elements costs less.
But again, without more details and without a good example to work with addressing that particular issue doesn't seem practical here.
The condition
x.AllocationDetailList[0] != null
will throw exception if there is no item in the AllocationDetailList. Instead you need to check
x.AllocationDetailList!=null && x.AllocationDetailList.Count>0.
Also .ToList() after SelectMany in your code will create a new list and items will be removed from that new list instead of unCompletedJobDetailsBO. You need to modify the remove function as below
unCompletedJobDetailsBO.ForEach(y => y.JobList.RemoveAll(x => ((x.AllocationDetailList != null && x.AllocationDetailList.Count>0)
?
x.AllocationDetailList[0].JobType == "D"
&& x.AllocationDetailList[0].JobUnCollectedID == null
&& x.AllocationDetailList[0].CurrentStatus == "5"
:
x.AllocationDetailList.Count > 1
)
));
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.
I have a question about LINQ query. Normally a query returns a IEnumerable<T> type. If the return is empty, not sure if it is null or not. I am not sure if the following ToList() will throw an exception or just a empty List<string> if nothing found in IEnumerable result?
List<string> list = {"a"};
// is the result null or something else?
IEnumerable<string> ilist = from x in list where x == "ABC" select x;
// Or directly to a list, exception thrown?
List<string> list1 = (from x in list where x == "ABC" select x).ToList();
I know it is a very simple question, but I don't have VS available for the time being.
It will return an empty enumerable. It won't be null. You can sleep sound :)
You can also check the .Any() method:
if (!YourResult.Any())
Just a note that .Any will still retrieve the records from the database; doing a .FirstOrDefault()/.Where() will be just as much overhead but you would then be able to catch the object(s) returned from the query
var lst = new List<int>() { 1, 2, 3 };
var ans = lst.Where( i => i > 3 );
(ans == null).Dump(); // False
(ans.Count() == 0 ).Dump(); // True
(Dump is from LinqPad)
.ToList returns an empty list. (same as new List<T>() );
In Linq-to-SQL if you try to get the first element on a query with no results you will get sequence contains no elements error. I can assure you that the mentioned error is not equal to object reference not set to an instance of an object.
in conclusion no, it won't return null since null can't say sequence contains no elements it will always say object reference not set to an instance of an object ;)
Other posts here have made it clear that the result is an "empty" IQueryable, which ToList() will correctly change to be an empty list etc.
Do be careful with some of the operators, as they will throw if you send them an empty enumerable. This can happen when you chain them together.
It won't throw exception, you'll get an empty list.