C# select duplicate using group - c#

I would like to select only from non-blank Names where any Group contains same ID multiple times:
Data Setup
var a1 = new { id = 3, Name = "", Group = "GroupA" };
var a2 = new { id = 2, Name = "", Group = "GroupA" };
var a3 = new { id = 3, Name = "", Group = "GroupA" };
var b1 = new { id = 4, Name = "B", Group = "GroupB" };
var b2 = new { id = 5, Name = "B", Group = "GroupB" };
var b3 = new { id = 5, Name = "B", Group = "GroupB" };
List<dynamic> group = new List<dynamic>();
group.Add(a1);
group.Add(a2);
group.Add(a3);
group.Add(b1);
group.Add(b2);
group.Add(b3);
Query:
var query1 = group.ToList()
.Where(s=>s.Name != "")
.GroupBy(x =>x.Group)
.Where(g => g.Count() > 1)
.SelectMany(y => y)
.ToList();
Console.WriteLine("output\n" + string.Join("\n", query1));
Returns
id = 4, Name = B, Group = GroupB
id = 5, Name = B, Group = GroupB
id = 5, Name = B, Group = GroupB
But what I wanted is the following:
id = 5, Name = B, Group = GroupB
id = 5, Name = B, Group = GroupB
What am I doing wrong?

Group by id and/or Name depending on your needs
.GroupBy(x => new {x.id, x.Name})
Given
var list = new[]
{
new {id = 3, Name = "", Group = "GroupA"},
new {id = 2, Name = "", Group = "GroupA"},
new {id = 3, Name = "", Group = "GroupA"},
new {id = 4, Name = "B", Group = "GroupB"},
new {id = 5, Name = "B", Group = "GroupB"},
new {id = 5, Name = "B", Group = "GroupB"}
};
Usage
var results = list
.Where(s => s.Name != "")
.GroupBy(x => new {x.id, x.Name})
// .GroupBy(x => x.id) <- depending on your needs
.Where(g => g.Count() > 1)
.SelectMany(y => y);
foreach (var result in results)
Console.WriteLine($"{result.id}, {result.Name}, {result.Group}");
Output
5, B, GroupB
5, B, GroupB

You are applying GroupBy to Group property. Instead of Grouping by Group property, use id property,
Input
var list = new[]
{
new {id = 3, Name = "", Group = "GroupA"},
new {id = 2, Name = "", Group = "GroupA"},
new {id = 3, Name = "", Group = "GroupA"},
new {id = 4, Name = "B", Group = "GroupB"},
new {id = 5, Name = "B", Group = "GroupB"},
new {id = 5, Name = "B", Group = "GroupB"}
};
Solution:
var query1 = list.ToList()
.Where(s=>s.Name != "")
.GroupBy(x =>x.id)
//^^^^^ This change you need to do
.Where(g => g.Count() > 1)
.SelectMany(y => y)
.ToList();
Output
5, B, GroupB
5, B, GroupB
Try it online

Related

Child list in join statement - LINQ

I have 3 collections
List<Brand> brands= new List<Brand>
{
new Brand { ID = 5, Name = "Toyota"},
new Brand { ID = 6, Name = "Mazda"},
new Brand { ID = 7, Name = "Seat"}
};
ModelParam par1 = new ModelParam() { Id = 1, fuelType = "Petrol", enginePower =110, engineTorque = 130 };
ModelParam par2 = new ModelParam() { Id = 2, fuelType = "Petrol", enginePower = 170, engineTorque = 290 };
ModelParam par3 = new ModelParam() { Id = 3, fuelType = "Diesel", enginePower = 140, engineTorque = 280 };
ModelParam par4 = new ModelParam() { Id = 4, fuelType = "Diesel", enginePower = 190, engineTorque = 320 };
List<Model> models = new List<Model>
{
new Model { Id = 1, Name = "CX5", brandId = 6, parameters = new List<ModelParam> {par1, par3} },
new Model { Id = 2, Name = "Corolla", brandId = 5, parameters = new List<ModelParam> {par2, par3} },
new Model { Id = 3, Name = "Leon", brandId = 7, parameters = new List<ModelParam> {par2, par4} }
};
As a result I want to have a query with combination of:
Brand - Model - FuelType - EnginePower.
I wrote this to join brands and model lists:
var result = models.Join(brands,
mod => mod.brandId,
b => b.ID,
(mod, b) => new { b.Name, mod.Name })
.ToList();
The problem is I can't extract fuelType and enginePower from ModelParams from params property in models List. Any tips?
Can this approach work for you?
var result = models.Join(
brands,
mod => mod.brandId,
b => b.ID,
(mod, b) => mod.parameters.Select(parameter => new {
Brand = b.Name,
Model = mod.Name,
FuelType = parameter.fuelType,
EnginePower = parameter.enginePower
}))
.SelectMany(pr => pr)
.ToList();
You should update your result selector Func a little bit and get the required values fuelType and enginePower from parameters collection in Model class. The following snippet will select only the first fuelType from parameters and max enginePower.
var result = models
.Join(brands, mod => mod.brandId, b => b.ID,
(mod, b) => new
{
Brand = b.Name,
Model = mod.Name,
FuelType = mod.parameters.Select(p => p.fuelType).FirstOrDefault(),
EnginePower = mod.parameters.Max(p => p.enginePower)
})
.ToList();
However, there a situation when model can have multiple values for fuelType and enginePower.
If you need to choose all combinations, just look through the parameters collection and then flatten a result using SelectMany
var result = models
.Join(brands, mod => mod.brandId, b => b.ID,
(mod, b) => mod.parameters.Select(p => new
{
Brand = b.Name,
Model = mod.Name,
FuelType = p.fuelType,
EnginePower = p.enginePower
}))
.SelectMany(_ => _)
.ToList();

Linq how to find max repeat items?

I have a list of object (ProductInfo).
ProductInfo contains an id, name, and an option.
Imagine this sample, i have this
ProductInfo Id => 1, Name => XXX, Option = A
ProductInfo Id => 1, Name => XXX, Option = B
ProductInfo Id => 2, Name => DEB, Option = A
ProductInfo Id => 2, Name => DEB, Option = B
ProductInfo Id => 2, Name => DEB, Option = C
ProductInfo Id => 3, Name => ZZZ, Option = D
....
....
We see we have 2 time the option A AND B for product 1 and 2.
My goal will be to obtain the max repeat item for each product in the list.
i would like to obtain as result this :
Id = 1, Name = XXX = A, count = 2
Id =2, Name = DEB, count = 2
How i can do that ?
thanks for your time
try to do this code:
var list = new List<ProductInfo> {
new ProductInfo { Id = 1, Name = "XXX", Option = "A"},
new ProductInfo { Id = 1, Name = "XXX", Option = "B" },
new ProductInfo { Id = 2, Name = "DEB", Option = "A" },
new ProductInfo { Id = 2, Name = "DEB", Option = "B"},
new ProductInfo { Id = 2, Name = "DEB", Option = "C" },
new ProductInfo { Id = 3, Name = "ZZZ", Option = "D" }
};
var x = from p in list
group p by new { p.Id, p.Name, p.Option } into g
select new
{
Id = g.Key.Id,
Name = g.Key.Name,
Count = list.Count(m => m.Name == g.Key.Name)
};
var t = x.Distinct();
You can use GroupBy on the Name and Id parameter. Sorry read that wrong at first.

How to merge 2 listitems

I have 2 listitems
First
{Id = 1, Name = "a"}{Id = 2, Name = "b"}{Id = 3, Name = "c"}
Second
{Id = 2, Name = "b"}{Id = 3, Name = "c"}{Id = 4, Name = "d"}
how to merge them and get a listitem like:
{Id = 1, Name = "a"}{Id = 2, Name = "b"}{Id = 3, Name = "c"}{Id = 4, Name = "d"}
Something like this ?
class items {
public int id;
public string name;
}
static void Main(string[] args)
{
var list = new List<items>();
list.Add(new items {id=1 , name="a"});
list.Add(new items { id = 2, name = "b" });
list.Add(new items { id = 3, name = "c" });
var list1 = new List<items>();
list1.Add(new items { id = 2, name = "b" });
list1.Add(new items { id = 3, name = "c" });
list1.Add(new items { id = 4, name = "d" });
var c = list.Select(b=> new {b.id, b.name});
var d = list1.Select(b => new { b.id, b.name });
var merge = c.Concat(d).Distinct().ToList();
foreach (var item in merge)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
var list1 = new[]{new {Id = 1, Name = "a"},new {Id = 2, Name = "b"}, new{Id = 3, Name = "c"}}.ToList();
var list2 = new[]{new {Id = 1, Name = "a"},new {Id = 2, Name = "b"}, new{Id = 3, Name = "c"}}.ToList();
list1.AddRange(list2);
Then list1 is the merged list.
You can use the "AddRange" or "Union" or "Concat" functions of c#
e.g
var list1 = new[]{new {Id = 1, Name = "a"},new {Id = 2, Name = "b"}, new{Id = 3, Name = "c"}}.ToList();
var list2 = new[]{new {Id = 1, Name = "a"},new {Id = 2, Name = "b"}, new{Id = 3, Name = "c"}}.ToList();
then
var MergedResult = list1.Union(list2).ToList();
or
var MergedResult = list1.AddRange(list2).ToList();
also you can use Concat as well...
see the difference amongst them here .NET List Concat vs AddRange

How to Union linq output from different tables and return

How can I perform a union between two linq results and return the results to a view?
public ActionResult ShowAllStudents()
{
var StudentA = (from p in stud.Student_A.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index).ToList();
var StudentB = (from p in stud.Student_B.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index).ToList();
ViewData.Model = StudentA.Union(StudentB);
return View();
}
I get the following error if I try the way showed above:
'System.collections.Generic.List<Student.Models.Student_A> does not contain a definition for 'Union' and the best extension method overload 'System.Linq.Queryable.Union<TSource>(System.Linq.IQueryable<TSource>, System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments
Avoid the queries materialization. Remove the .ToList() calls.
Update:
class Program
{
static void Main(string[] args)
{
var Student_A = new[]{
new {StudentId = 1, Index = 23, Name = "Lucas"},
new {StudentId = 2, Index = 71, Name = "Juan"},
new {StudentId = 3, Index = 85, Name = "Noelia"}
};
var Student_B = new[]{
new {StudentId = 6, Index = 31, Name = "Marcelo"},
new {StudentId = 7, Index = 72, Name = "Manuel"},
new {StudentId = 8, Index = 95, Name = "Roberto"}
};
var StudentA = (from p in Student_A.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index);
var StudentB = (from p in Student_B.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index);
var all = StudentA.Union(StudentB);
all.ToList().ForEach(x=> Console.WriteLine(x.Name));
}
}
Which is the diference with this snippet?
Update 2:
Ok, I got it. The problem is Student_A´s elements and Student_B's elements are different types. I could reproduce the error you have as follow
class Program
{
static void Main(string[] args)
{
var Student_A = new[]{
new {StudentId = 1, Index = 23, Name = "Lucas"},
new {StudentId = 2, Index = 71, Name = "Juan"},
new {StudentId = 3, Index = 85, Name = "Noelia"}
};
var Student_B = new[]{
new {StudentId = 6, Index = 31, Name = "Marcelo", I=0}, // extra property
new {StudentId = 7, Index = 72, Name = "Manuel", I=0},
new {StudentId = 8, Index = 95, Name = "Roberto", I=0}
};
var StudentA = (from p in Student_A.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index);
var StudentB = (from p in Student_B.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index)
var all = StudentA.Union(StudentB);
all.ToList().ForEach(x=> Console.WriteLine(x.Name));
}
However, if we make both with the same type it works. Take a look at the follow example:
class Program
{
static void Main(string[] args)
{
var Student_A = new[]{
new {StudentId = 1, Index = 23, Name = "Lucas"},
new {StudentId = 2, Index = 71, Name = "Juan"},
new {StudentId = 3, Index = 85, Name = "Noelia"}
};
var Student_B = new[]{
new {StudentId = 6, Index = 31, Name = "Marcelo", I=0},
new {StudentId = 7, Index = 72, Name = "Manuel", I=0},
new {StudentId = 8, Index = 95, Name = "Roberto", I=0}
};
var StudentA = (from p in Student_A.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index)
.Select(x=> new {StudentId = x.StudentId, Index = x.Index, Name = x.Name });
var StudentB = (from p in Student_B.Where(a => a.StudentId != 0)
group p by p.Index into g
select g.FirstOrDefault()).Distinct().OrderBy(a => a.Index)
.Select(x=> new {StudentId = x.StudentId, Index = x.Index, Name = x.Name });
var all = StudentA.Union(StudentB);
all.ToList().ForEach(x=> Console.WriteLine(x.Name));
}
The difference is in the line:
.Select(x=> new {StudentId = x.StudentId, Index = x.Index, Name = x.Name });

Sorting an IEnumerable in LINQ

How to sort the given examples.
IEnumerable<extra> eList = new List<extra>()
{
new extra{ id = 1, text = "a"},
new extra{ id = 2, text = "g"},
new extra{ id = 3, text = "i"},
new extra{ id = 4, text = "e"},
new extra{ id = 5, text = "f"},
new extra{ id = 6, text = "d"},
new extra{ id = 7, text = "c"},
new extra{ id = 8, text = "h"},
new extra{ id = 9, text = "b"}
};
IEnumerable<sample> sam = new List<sample>()
{
new sample{ id = 1, name = "sample 1", list = new List<int>{1,5,6}},
new sample{ id = 2, name = "sample 1", list = new List<int>{2,9}},
new sample{ id = 3, name = "sample 1", list = new List<int>{8,3,7}},
new sample{ id = 4, name = "sample 1", list = new List<int>{3,4,8}},
new sample{ id = 5, name = "sample 1", list = new List<int>{1,5,7}},
new sample{ id = 6, name = "sample 1", list = new List<int>{6,9,7}}
};
I have this code to sort and join the sample list to the extra object above.
var s2 = (from d1 in sam
select new
{
name = d1.name,
id = d1.id,
list =
(
from d2 in d1.list
join e in eList on d2 equals e.id
select new {
id = d2, text = e.text
}
).OrderBy(item => item.text.FirstOrDefault())
});
The code above works fine, it joined the two data and sorted the values for the list. But what I want is the output above 's2' will be sorted again by its 'list' value by 'list.text'.
So possible output above must be:
{ id = 1, name = "sample 1", list = {'a','f','d'}},
{ id = 5, name = "sample 1", list = {'a','f','c'}},
{ id = 2, name = "sample 1", list = {'g','b'}},
{ id = 4, name = "sample 1", list = {'i','e','h'}},
{ id = 6, name = "sample 1", list = {'d','b','c'}},
{ id = 3, name = "sample 1", list = {'h','i','c'}},
Is this possible in LINQ?
thanks
var newsam = sam.Select(s => new
{
id = s.id,
name = s.name,
list = s.list
.Select(l => eList.FirstOrDefault(e => e.id == l).text)
.OrderBy(e => e)
.ToList()
}
).OrderBy(s => s.list.FirstOrDefault())
.ToList();
EDIT
So, the inner lists are sorted by the text value of the eList; and the outer list is sorted by the first element of the inner list
EDIT
var s2=(from d1 in sam
select new
{
name = d1.name,
id = d1.id,
list =
(
from d2 in d1.list
join e in eList on d2 equals e.id
select e.text
).OrderBy(item => item).ToList()
}).OrderBy(item => item.list.FirstOrDefault());

Categories