Can we create a grouped list to normal list? - c#

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

Related

LiteDb auto-increment id sub list of class

I have these classes and got issue with auto increase id of sub lists:
class A
{
public int Id { get; set; }
public string Value { get; set; }
public List<B> Bs { get; set; }
}
class B
{
public int Id { get; set; }
public string Value { get; set; }
public List<C> Cs { get; set; }
}
class C
{
public int Id { get; set; }
public string Value { get; set; }
}
How can I automatically increase the id of the B and C? I can add values but id inside the sub list they're always 0.
In general, an A item can contain B with the same id, as well as different B items can contain C with the same id.
If you just need different ids, you can assign them right in the code just like other properties.
If it is required to support consistency and assign a new id to every sub-item, the items should be stored in separate collections:
var collectionA = db.GetCollection<A>("a");
var collectionB = db.GetCollection<B>("b");
var collectionC = db.GetCollection<C>("c");
BsonMapper.Global.Entity<A>().DbRef(x => x.Bs, "b");
BsonMapper.Global.Entity<B>().DbRef(x => x.Cs, "c");
foreach (var c in a.Bs.SelectMany(x => x.Cs).Where(x => x.Id == 0))
collectionC.Insert(c);
foreach (var b in a.Bs.Where(x => x.Id == 0))
collectionB.Insert(b);
collectionA.Insert(a);
More details about sub-documents are available in the documentation

Data is ignored at ThenInclude() for nested List property

I have more of a special case, and I am not sure what the reason is for what my issue is happening.
I have a class A with nested class B which also has a nested class C
public class A
{
[Key]
public int Id { get; set; }
public int Name { get; set; }
public List<B> Bs{ get; set; }
}
public class B
{
[Key]
public int Id { get; set; }
public int Name { get; set; }
public List<C> Cs{ get; set; }
[ForeignKey(nameof(A))]
public int AId{ get; set; }
}
public class C
{
[Key]
public int Id { get; set; }
public int Name { get; set; }
[ForeignKey(nameof(B))]
public int BId{ get; set; }
}
Now the problem that I have is that the values of class C aren't included into class B when class A is called alongside with Include(), respectively ThenInclude() methods.
The way values are brought from DB Tables is using a normal SQL Query combined with LINQ.
var query = from queryResult in _dbSet.Include(a => a.B).ThenInclude(B => b.C)
select new ResultModel()
{
Name = queryResult.Name
B = queryResult.B
}
The normal properties of B are being brought from db and mapped automatically to it, but the values for the nested List property aren't for some reason.
Do I need to make additional changes to select query in order for values of nested class C property be mapped into class B?
I hope the question was not too confusing.
The problem I had was the property being ignored because of not being included in the select. So the solution would be to change from
var query = from queryResult in _dbSet.Include(a => a.B).ThenInclude(B => b.C)
select new ResultModel()
{
Name = queryResult.Name
B = queryResult.B
}
to
var query = from queryResult in _dbSet.Include(a => a.B).ThenInclude(B => b.C)
select new ResultModel()
{
Name = queryResult.Name
B = queryResult.B.Select(x =>
new C {
Id = x.Id,
Name = x.Name,
}).ToList()
You can read more about this issue here.

Flatten a list which one of its properties is another list of object

I have the following classes:
public class Owner
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Main
{
public string Id { get; set; }
public string Name { get; set; }
public List<Owner> Owners { get; set; }
}
I want to convert List<Main> to List<FlatList> where FlatList is
public class FlatList
{
public string Id { get; set; } // Id from Main
public string Name { get; set; } // Name from Main
public string OwnerId { get; set; } // Id from each Owner in a Main's Owner
public string OwnerName { get; set; } // Name from each Owner in a Main's Owner
}
Unfortunately I haven't been able to figure out the LinQ query to perform this operation.
You should use SelectMany to flatten a sequence of Main objects:
Projects each element of a sequence to an IEnumerable and flattens
the resulting sequences into one sequence.
So it projects each Main object into sequence of FlatList objects and then flattens resulting sequences into one FlatList sequence
var flatList = mainList.SelectMany(m =>
m.Owners.Select(o =>
new FlatList {
Id = m.Id,
Name = m.Name,
OwnerId = o.Id,
OwnerName = o.Name
})).ToList()
List<Main> mainList = ...
var flatList = (
from main in mainList
from owner in main.Owners
select new FlatList {
Id = main.Id, Name = main.Name,
OwnerId = owner.Id, OwnerName = owner.Name
}).ToList();
You can do that using linq (secret looping behind the scenes):
from m in mainList
from o in m.Owners
select new FlatList
{
Id = m.Id,
Name = m.Name,
OwnerId = o.OwnerId ,
OwnerName = o.OwnerName
};

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

LINQ Grouping on multiple properties

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
...
}

Categories