LINQ Grouping on multiple properties - c#

I like to group a collection of objects based on some of their properties. I can group them, but after grouping them, how can I put each group of results into their own separate list so I process each list accordingly. Here's an example of what I have thus far:
public class INPRKData
{
public string rptDate { get; set; }
public string clientNumber { get; set; }
public string fileNumberId { get; set; }
public string cycleType { get; set; }
public string streamType { get; set; }
public string branchCode { get; set; }
}
grouping based on three properties: clientNumber, fileNumberId and streamType...
var grouped =
from d in INPRKDataCollection
group d by new { d.clientNumber, d.fileNumberId, d.streamType };

IEnumerable<List<INPRKData>> lists = from grp in grouped
select grp.ToList()

Each grouping will implement IEnumerable<INPRKData> and iterate over the items in the group, so you can just iterate over the groups:
foreach(var group in grouped)
{
var list = group.ToList(); // the items in that group
...
}

Related

Can we create a grouped list to normal list?

Here it is just an example. Suppose we have class Grouped (Items are gruoped by group name) as given below:
public class Grouped
{
public int Id { get; set; }
public string GroupName { get; set; }
public List<Item> Items{ get; set; }
}
public class Item
{
public string ItemName { get; set; }
}
What i need to do is to make a list of Normal Class from the above Grouped Object using only linq c# but not using ForEach or ForLoop.
pubic class Normal
{
public int Id { get; set;}
public string GroupName { get; set;}
public string ItemName { get; set;}
}
here is an example of list
Id
Name
Item
1
A
X
1
A
Y
2
B
Y
3
C
X
3
C
Y
3
C
Z
If you have a collection of Grouped (and you should, based on the desired output, otherwise there is no source for multiple Ids) you can use SelectMany to flatten a nested collection. Something along this lines:
IEnumerable<Grouped> grouped = ...;
var result = grouped
.SelectMany(g => g.Items.Select(i => new Normal
{
Id = g.Id,
GroupName = g.GroupName,
ItemName = i.ItemName
}))
.ToList();

Collapse non-repeated columns into sublist c#

I have list of objects "orginalobject" is like below and also figure . This is populated from database
orginalobject.monitorName
orginalobject.ProcessGUID
orginalobject.Apikey
orginalobject.AIRSTATION
orginalobject.variableName
orginalobject.id
orginalobject.AIRSTATIONChannel
As in Attached image you can see some columns are repeated that is
monitorName
ProcessGUID
Apikey
AIRSTATION
And non repeatable columns are
variableName
id
AIRSTATIONChannel
so I want list should be grouped by these repeating columns and other columns should become list of this object using lamda or linq
object.monitorName
object.ProcessGUID
object.Apikey
object.AIRSTATION
Object.List<Subobjects> list
And Subobjects class will be like
ObjectSubobjects.variableName
ObjectSubobjects.id
ObjectSubobjects.AIRSTATIONChannel
If I understand you question correctly, you just want to group list of objects by their non-unique monitorName, ProcessGUID, Apikey and AIRSTATION properties used as a key and for each of these groups create list of sub-objects with the remaining unique properties?
This can be done with the following simple linq query. First it uses GroupBy to create groups of originalobjects with the same values of non-unique properties. I used ValueTuple struct to represent combination of non-unique properties as a single object used as a key for grouping. But from provided image it seems that it might be superfluous and that any of the non-unique properties alone used as a grouping key should be sufficient. The rest of the query contains just two projections (Select) that copies values from originalobjects to newly created GroupObjects and ObjectSubobjects.
var groupedObjects = objects.GroupBy(o => (o.monitorName, o.ProcessGUID, o.Apikey, o.AIRSTATION))
.Select(g => new GroupObject()
{
monitorName = g.Key.monitorName,
ProcessGUID = g.Key.ProcessGUID,
Apikey = g.Key.Apikey,
AIRSTATION = g.Key.AIRSTATION,
list = g.Select(s => new ObjectSubobjects()
{
variableName = s.variableName,
id = s.id,
AIRSTATIONChannel = s.AIRSTATIONChannel
})
.ToList()
})
.ToList();
public class orginalobject
{
public string monitorName { get; set; }
public Guid ProcessGUID { get; set; }
public Guid Apikey { get; set; }
public string AIRSTATION { get; set; }
public string variableName { get; set; }
public Guid id { get; set; }
public int AIRSTATIONChannel { get; set; }
}
public class GroupObject
{
public string monitorName { get; set; }
public Guid ProcessGUID { get; set; }
public Guid Apikey { get; set; }
public string AIRSTATION { get; set; }
public List<ObjectSubobjects> list { get; set; }
}
public class ObjectSubobjects
{
public string variableName { get; set; }
public Guid id { get; set; }
public int AIRSTATIONChannel { get; set; }
}

how to use Except or Remove method based on nested list condition

I have a complex object with multiple levels of nesting. An Order contains several Orderlines internally and each Orderline has Product list. I need to delete/remove the Orderlines that have products whose UseByDate is older than today.
I've tried
orders.Orderlines.RemoveAll(x => x.products.FindAll(z => z.UseByDate > DateTime.Now);
My classes:
class Order
{
public int Orderid { get; set; }
public string customerName { get; set; }
public List<Orderline> Orderlines { get; set; }
}
public class Orderline
{
public int orderid { get; set; }
public string Name { get; set; }
public int orderlineid { get; set; }
public List<Product> products { get; set; }
}
public class Product
{
public int orderlineid { get; set; }
public DateTime UseByDate { get; set; }
}
RemoveAll removes all the elements that match the conditions defined by the specified predicate. i.e. The bit in the brackets needs to return a boolean.
orders.Orderlines.RemoveAll(o => o.products.Any(p => p.UseByDate > DateTime.Now))
foreach(var order in orders.Orderlines) {
bool isValid = true;
foreach(var product in order.Products) {
if (DateTime.Compare(product.UseByDate, DateTime.Now) > 0) {
isValid = false;
}
}
if (isValid = false) {
orders.OrderLines.Remove(order);
}
}
i think something like this should accomplish that (old fashion way instead of using linq).
When using linq you should return a list that has all the objects (orderlines) that have invalid orderlines. then have a foreach that removes them. To my knowledge it is best practice to separate the selecting/finding and the removing/action elements (but i could be wrong :D )

Filter list of object by value of property of nested list equals value of same property of another element of the nested list

Ok, I have this class:
public class Person
{
public int Id { get; set; }
public string SpecialNumber { get; set; }
public IQueryable<Game> Games { get; set; }
}
And these classes:
public class Game
{
public int Id { get; set; }
public string Name { get; set; }
public decimal? RamNeeded { get; set; }
public Town Town { get; set; }
}
public class Town
{
public int Id { get; set; }
public string TownName { get; set; }
public string CountryName { get; set; }
public string StateName { get; set; }
}
I need to display the SpecialNumber of the Person, whose Sum of games' RamNeeded is greatest, from People (IQueryable<Person>), who have games:
From more than 2 different Towns in one State.
From different States in one Country(This means that there are at least two games with different States).
From different Countries (This means that there are at least two games with different Countries).
I need to make this query on LINQ or SQL. Hope you can help.
Anytime you need to do something with the elements of a set that have equal value of some property, you can use GroupBy method (or group clause in query syntax).
Then you can use different aggregate functions for each group of elements. For instance, in your case Count can be used to check if the group contains a specific amount of items.
With that being said, the query in question could be something like this
IQueryable<Person> persons = ...;
var query =
from person in persons
let countryGroups = person.Games.GroupBy(game => game.Town.CountryName)
where countryGroups.Count() > 1 // (3)
&& countryGroups.Any(countryGroup =>
countryGroup.GroupBy(game => game.Town.StateName).Count() > 1 // (2)
&& countryGroup.GroupBy(game => game.Town.StateName).Any(stateGroup =>
stateGroup.GroupBy(game => game.Town.Id).Count() > 2)) // (1)
let RamNeeded = person.Games.Sum(game => game.RamNeeded) // in case you need to include it in the select
orderby RamNeeded descending
select person.SpecialNumber;
var result = query.FirstOrDefault();

Get a list of unrepeated possible values of a field using Linq

I have a List of items of type DataItem (List<DataItem>):
public class DataItem
{
public DataItem() { }
public string Title { get; set; }
public string Url { get; set; }
public string Category { get; set; }
}
There may be many items with the same string in Category field.
How can I extract a list of different possible categories using Linq?
What I want as a result is a List<string> which has all the values found for Category property, but doesn't have repeated values.
You can use the Distinct method:
var result = itemsList.Select(n => n.Category).Distinct().ToList();
yourList.Select(item => item.Category).Distinct().ToList();

Categories