List is empty after linq operation - c#

I have problem to understend what is happening in foreach loop- listOfBookedTimes successfuly gets elements that I want, but after execution of the next line listOfBookedTimes is empty. Why? (All lists contain DateTime)
foreach (var day in allDays)
{
list = Rep.GetListOfWorkingHours(fullDayWorkingHours, day, sPWorkingHours);
bookedTimes = _bookingsService.GetBookedTimes(day, providerId);
foreach (var b in bookedTimes)
{
var listOfBookedTimes = list.Where(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
list.RemoveAll(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
listOfBookedTimes.Select(m => m.Year - 50);
list.AddRange(listOfBookedTimes);
}

You are removing all elements from the list in this statement
list.RemoveAll(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
notice that
listOfBookedTimes = list.Where(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
and
list.RemoveAll(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
have the same condition
You can execute ToList() in order to get a new copy of the list, so that removing items from the original list won't affect it:
listOfBookedTimes = list.Where(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay)).ToList();
BUT
listOfBookedTimes still holds the references to the original items from the list so while adding removing elements to both those lists won't affect each other, modifying properties of single item that is contained by both lists will be applied to both of them.

Your problem is not the RemoveAll but rather the fundemental understanding of LinQ and yield return.
When you call
list.Where(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay));
it is not executed but rather returns an enumerator that will filter the collection on iteration. In the next line you remove all entries you wanted to fetch in the previous line.
When you finally iterate the collection in
list.AddRange(listOfBookedTimes);
it is already empty.
Solution: Add .ToArray() or .ToList() after the Where and it should work as expected. Like this:
var listOfBookedItems = list.Where(m => m.TimeOfDay == (b.TimeOfAppointment.TimeOfDay))
.ToList();

Related

Cannot access groupBy data Linq C#

Inside method I have a list that contains grouped data:
var listofData = _context.DBONE.where(x => x.Id==3 && x.Status!=0)
.GroupBy(x => new { x.Name, x.Class })
.Select(q => new { Result = q.ToList() }).ToList();
if (methodParam == 10)
{
data = listofData.Where(x => FunctionCheck(---CANNOT ACCESS THE FIELDS FROM GROUP DATA TO PASS AS PARAMETERS---) == 10).ToList();
}
And this is the function that will receive 2 parameter from the grouped data:
private int FunctionCheck(int id, string name)
{...}
But, I cannot access the desired field inside 'listofData'. I can access only in case the listofData is not using groupBy().
If I understand what you are trying to do correctly, you are able to access your data but you are actually creating a "list of a list"
Watch my example, I think I have reproduced your scenario here:
As you can see, I then have a "result" which contains a list of users where Id == 3. The problem is that you create a new anonymous object with a props that is a list. So if you try the last thing you see in my image above, I think you will be able to access your rows.
The reason is that after your GroupBy call, the result is of a grouping type - every item of your list is an Enumerable of the original item, so you would have to operate on that grouping in a following manner:
// Groups such that all items in that group pass your check
listofData
.Where(group => group.All(item => FunctionCheck(item.Id, item.Name) == 10))
.ToList();
// Groups where at least one item matches
listofData
.Where(group => group.Any(item => FunctionCheck(item.Id, item.Name) == 10))
.ToList();
The desired outcome is not really clear from the question but this is the step you are likely missing.
Another approach which might be potentially useful is pre-filter the colleciton of items before grouping them:
var listOfGroupedDatas = _context.DBONE
.Where(x => x.Id ==3 && x.Status != 0 && FunctionCheck(item.Id, item.Name) == 10)
.GroupBy(x => new { x.Name, x.Class })
.ToList();
// This will result in a list of groupings in which all items pass your check
I think you want to call SelectMany to project into one dimensional array.
var listofData = _context.DBONE.where(x => x.Id==3 && x.Status!=0)
.GroupBy(x => new { x.Name, x.Class })
.SelectMany(q => q.ToList()).ToList();

Retrieve the item from the list

I am trying to get the list of Courses from the courseData list item.
However, the following returns me boolean.
var course = courseData.Courses.Select(x => x.Entities.Select(a => a.courseId == courseDto.Id)).FirstOrDefault();
Currently, course is of type IEnumerable<bool> because in your inner Select clause you're projecting from some type a and returning a.courseId == courseDto.Id (bool) which results in an IEnumerable<bool> after the provided lambda is executed for each element of x.Entities.
Once the execution of the outer Select clause is performed this then results in having a type IEnumerable<IEnumerable<bool>> which when you then call FirstOrDefault() upon; simply results in retrieving the first IEnumerable<bool> element.
Now, you're most likely looking for the Where clause so that you can retain all the elements that pass the predicate a => a.courseId == courseDto.Id. We will then flatten the IEnumerable<IEnumerable<Entity>> into IEnumerable<Entity> and then collect to a list or retrieve the first element if exists else the default for reference types (null).
To retrieve a list of courses.
var course =
courseData.Courses
.SelectMany(x => x.Entities.Where(a => a.courseId == courseDto.Id))
.ToList();
To retrieve the first item from the list of courses.
var course =
courseData.Courses
.SelectMany(x => x.Entities.Where(a => a.courseId == courseDto.Id))
.FirstOrDefault();
var Result = Course_Object.Where(u => u.Id == 1).FirstOrDefault();

dynamic filters in asp.net mvc 4

I want to do something like this:
var list = db.Respaldoes.Where(x => x.type == "Backup");
if (condicion1)
list.Where(x => x.entity == "GIELCJLT03");
if (condicion2)
list.Where(x => x.activity_type == "0");
I don't know if something like this is possible, I get the list but the filters are never applied.
You could try something like this:
var list = db.Respaldoes.Where(x => x.type == "Backup");
if (condicion1)
list = list.Where(x => x.entity == "GIELCJLT03");
if (condicion2)
list = list.Where(x => x.activity_type == "0");
Initially the list when the Where clause, x => x.type == "Backup", will be executed it will give you the initial list you refer to. Then, if the condicion1 is true, you will make a second fitering and you will assign the result to list. There again you have deffered execution. Only when list will be requested to be consumed by another piece of your code will be executed -hence the name deffered execution. The same holds for the second condicion and so on.
Where returns an IEnumerable<T>, which defers the execution until a later action forces the query to be resolved. If you want to resolve your query, immediately execute it with ToList().
In addition, you are not actually doing anything with your filtered list. By reassigning the filtered list to your original list object, it will update the collection with the filter, removing objects that do not match your predicate.
var list = db.Respaldoes.Where(x => x.type == "Backup");
if (condicion1)
list = list.Where(x => x.entity == "GIELCJLT03").ToList();
if (condicion2)
list = list.Where(x => x.activity_type == "0").ToList();

List where Clause with Remove

The code below works successfully to remove if a value exists in a list. How do I add a where clause such that only for list items where sType = "File"
MyGlobals.lstNewItems.RemoveAll(item => item.sItemName == rows[i].Cells[0].Value.ToString());
Pseudo Code for what i want
MyGlobals.lstNewItems.Where(y => y.sType == "File").RemoveAll(item => item.sItemName == rows[i].Cells[0].Value.ToString());
If you want to remove all of the items where both conditions are true, then simply AND them together:
MyGlobals.lstNewItems.RemoveAll(item =>
item.sItemName == rows[i].Cells[0].Value.ToString()
&& item.sType == "File");

Using Where on a list which is contained in another list?

Let's say I have a list called list1. This list1 contains another list, called list2. Now I want to check if list2 in list1 contains certain elements and return another list.
list3 = list1.list2.Where(p => p.something == 1)
Something like that?
This solution will return conditioned items in the inner list.
var result = list.SelectMany(l => l.InnerList)
.Where(p => p.something == 1);
If you want to get items in the outer list which meets the condition, use:
var another = list.Where(l => l.InnerList.Any(p => p.something == 1));
Take a look at the SelectMany function.

Categories

Resources