Below i have a snippet of code which outputs a list of Appointments based on clients, some clients can have more than one appointment but the latest one is the one that needs to be outputted for said client
the output is not grouping at all and for some reason i cannot figure why the heck not
foreach (ClientRecord client in clients)
{
List<ReturnRecord> records = db.Appointments
.AsNoTracking()
.Include(rec => rec.Property)
.Include(rec => rec.Property.Address)
.Include(rec => rec.AppointmentType)
.ToList()
.Where(rec => rec.ClientID == client.ID)
.Select(rec => new ReturnRecord
{
ClientName = $"{client.FirstNames} {client.Surnames}",
PropertyAddress = $"{rec.Property.Address.FormattedAddress}",
AppStatus = $"{rec.AppointmentStatus.Name}",
StockStatus = $"{rec.Property.Stocks.FirstOrDefault().StockStatus.Name}",
LastUpdated = rec.LastUpdated
})
.ToList();
returnList.AddRange(records);
}
returnList.GroupBy(rec => rec.PropertyAddress);
return Ok(returnList);
here is an attachment of the screen grab of the output
You need to assign result of GroupBy() to variable:
returnList = returnList.GroupBy(rec => rec.PropertyAddress).ToList();
Make sure to actually use the new IEnumerable that the .GroupBy() Method returned.
If you want to return a List you need to use a workaround:
Get the IEnumerable<IGrouping<int, ReturnRecord>> from the .GroupBy()
Use .SelectMany() to select all elements and save them into an IEnumerable
Now you can convert your IEnumerable into a List with .List()
Example:
// Longer Alternative
IEnumerable<IGrouping<int, ReturnRecord>> groups = resultList
.GroupBy((rec => rec.PropertyAddress);
IEnumerable<ReturnRecord> result = groups.SelectMany(group => group);
List<ReturnRecord> listResult = result.ToList();
return Ok(listResult);
// Shorter Alternative
IEnumerable<IGrouping<int, ReturnRecord>> groups = resultList
.GroupBy((rec => rec.PropertyAddress);
IEnumerable<ReturnRecord> result = groups.SelectMany(group => group);
return Ok(result.ToList());
Related
I need to grouping in the result of my query. The main problem is that when I use GroupBy, the return type of GroupBy statement is IGrouping that is different from the return type of my method which is List<MyViewModel>. So theses two types does not match. Now the first option is to change the return type of my method. In this case how I can access to the properties of my ViewModel in view layer(HTML part of Razor Page)?
Is there any option to using GroupBy without changing the return type of my method?
public List<MultimediaViewModel> Search(MultimediaSearchModel searchModel)
{
var query = _hContext.Multimedias.Include(x => x.Ceremony)
.Select(g => new MultimediaViewModel
{
Id = g.Id,
Title = g.Title,
CeremonyId = g.CeremonyId,
Ceremony = g.Ceremony.Title,
FileAddress = g.FileAddress,
}).AsEnumerable().GroupBy(g => g.CeremonyId).ToList();
if (!string.IsNullOrWhiteSpace(searchModel.Title))
query = query.Where(g => g.Title.Contains(searchModel.Title)).ToList();
if (searchModel.CeremonyId != 0)
query = query.Where(g => g.Key == searchModel.CeremonyId).ToList();
return query;
}
the above code is not working because of the difference between method return type and Group by return type.
without knowing your business needs completely I can offer 2 ways to get around this
use the GroupBy outside the method, use the Search method to return a list and then use GroupBy to group it
if you only need to return a list of MultimediaViewModel for a specific CeremonyId, you can search the list of IGrouping to get a specific sub list
public List<MultimediaViewModel> Search(MultimediaSearchModel searchModel)
{
var query = _hContext.Multimedias.Include(x => x.Ceremony).Select(g => new MultimediaViewModel
{
Id = g.Id,
Title = g.Title,
CeremonyId = g.CeremonyId,
Ceremony = g.Ceremony.Title,
FileAddress = g.FileAddress
}).GroupBy(g => g.CeremonyId).ToList();
return query.FirstOrDefault(g=>g.Key==searchModel.CeremonyId).ToList();
//you can just use Where to find all of the MultimediaViewModel instead of using GroupBy
EDIT
maybe return the result as a Dictionary
public Dictionary<string, List<MultimediaViewModel>> Search(MultimediaSearchModel searchModel)
{
var query = _hContext.Multimedias.Include(x => x.Ceremony).Select(g => new MultimediaViewModel
{
Id = g.Id,
Title = g.Title,
CeremonyId = g.CeremonyId,
Ceremony = g.Ceremony.Title,
FileAddress = g.FileAddress
}).GroupBy(g => g.CeremonyId).ToList();
return query.ToDictionary(k => k.Key, v => v.ToList());
}
Am trying to refactor some data in order to display some charts.
I can't seem to figure out why using the following, it lists all the values at the top rather than being sequential like the source data.
var categories = VehicleSales.Select(v => v.name).Distinct().ToList();
var refactoredResults = new List<StackedColumnChart>();
foreach (var category in categories)
{
var subresult = VehicleSales.Where(x => x.vehicleType == category)
.GroupBy(x => x.vehicleType)
.Select(gcs => new StackedColumnChart
{
Category = category,
Values = gcs.Select(x => (int)x.data).DefaultIfEmpty(0).ToList()
}).ToList();
refactoredResults.AddRange(subresult);
}
Source Data:
Then the actual results and expected results:
Thanks in advance!
You can do that without loop and selecting a distinct values, just use GroupBy method and map each group to StackedColumnChart using Select
var refactoredResults = VehicleSales
.GroupBy(s => s.Category)
.Select(g => new StackedColumnChart
{
Category = g.Key,
Values = g.Select(s => s.Value).ToList()
})
.ToList();
If the original data is not sorted and you'll need to sort the values by week number, you can use OrderBy clause before selecting a values Values = g.OrderBy(s => s.WeekNumber).Select(s => s.Value).ToList()
I want to be able to find all orders with items that contain BOTH apples and oranges that I have in a list.
var itemToFind = new List<string>()
{
"apples",
"cookies"
};
How can I rewrite this so that Contains is dynamic?
This returns what I want but how do I make it loop through my list so that it is dynamic?
var query = result
.Where(o => o.OrderItems
.Any(i => i.Item.Name.Contains("apples")))
.Select(x => x)
.Where(y => y.OrderItems
.Any(b => b.Item.Name.Contains("cookies"))).ToList();
// returns 2 orders
Try something like this:
result.Where(o => o.OrderItems.Any(i => itemToFind.All(itf => i.Item.Name.Contains(itf)))).ToList()
This seems to work but not sure if that is the best way.
foreach (var item in listFacets)
{
// append where clause within loop
result = result
.Where(r => r.RecipeFacets
.Any(f => f.Facet.Slug.Contains(item)));
}
Edit: Code works fine, it was an other bug.
I had comment out the //department.IdAgency = reader.GetByte(2); line, in the created departmentList. When I removed the // then the IQueryable<string> with .Where works fine. Sorry for the inconvenience!
static List<Department> CreateDepartmentList(IDataReader reader)
{
List<Department> departmentList = new List<Department>();
Department department = null;
while (reader.Read())
{
department = new Department();
department.Id = reader.GetByte(0);
department.Name = reader.GetString(1);
//department.IdAgency = reader.GetByte(2);
if (!reader.IsDBNull(3))
{ department.IdTalkGroup = reader.GetInt16(3); }
departmentList.Add(department);
}
return departmentList;
}
Original question:
I have an IQueryable<string> query, that works. But how do I use .Where?
IQueryable<string> query = departmentList.AsQueryable()
.OrderBy(x => x.Name)
.Select(x => x.Name);
I have tried this, but it does not work:
IQueryable<string> query = departmentList.AsQueryable()
.OrderBy(x => x.Name)
.Where(x => x.IdAgency == idAgencySelected[0])
.Select(x => x.Name);
All the .Where() call does is apply a filtering method to each element on the list, thus returning a new IEnumerable.
So, for some IQueryable<string>...
IEnumerable<string> results = SomeStringList.Where(s => s.Contains("Department"));
...You would get a list of strings that contain the word department.
In other words, by passing it some boolean condition that can be applied to a member of the queryable collection, you get a subset of the original collection.
The reason your second block of code does not work, is because you're calling a method or property that does not belong to string. You may want to consider querying against the more complex type, if it has identifier data, and then take the names of the elements and add them to some list instead.
I have an object that has a list of another object in it. i.e Object1 contains List<Object2>.
Assuming this is the definition of object 2:
public class Object2
{
string code,
string name,
decimal amount
}
I want to be a able to make a list2 from the list whose value will contain what something similar to what a select name, code, sum(amount) group by code kinda statement could have given me
this is what i did but it didnt contain what i needed on passing through.
var newlist = obj2List.GroupBy(x => x.code)
.Select(g => new { Amount = g.Sum(x => x.amount) });
I want code and name in the new list just like the sql statement above.
You're almost there:
var newlist = obj2List.GroupBy(x => x.code)
.Select(g => new
{
Code = g.First().code,
Name = g.First().name,
Amount = g.Sum(x => x.amount)
});
This groups the items by code and creates an anonymous object for each group, taking the code and name of first item of the group. (I assume that all items with the same code also have the same name.)
If you are grouping by code and not by name you'd have to choose something for name from the list, perhaps with First() or Last() or something.
var newlist = obj2List.GroupBy(x => x.code).Select(g => new {
Code = g.Key,
Name = g.First().name,
Amount = g.Sum(x => x.amount)
});
var query = Object1.Obj2List
.GroupBy(obj2 => obj2.code)
.Select(g => new {
Names = string.Join(",", g.Select(obj2.name)),
Code = g.Key,
Amount = g.Sum(obj2 => obj2.Amount)
});
Since you group by code only you need to aggregate the name also in some way. I have used string.Join to create a string like "Name1,Name2,Name3" for each code-group.
Now you could consume the query for example with a foreach:
foreach(var x in query)
{
Console.WriteLine("Code: {0} Names: {1} Amount: {2}"
, x.Code, x.Names, x.Amount);
}
Instead of using the LINQ Extension Methods .GroupBy() and .Select() you could also use a pure LINQ statement which is way easier to read if you come from a SQL Background.
var ls = new List<Object2>();
var newLs = from obj in ls
group obj by obj.code into codeGroup
select new { code = codeGroup.Key, amount = codeGroup.Sum(s => s.amount) };