Anish Sinha
Anish Sinha

Reputation: 139

Is there a way to find common elements in grouped lists in c#?

 List<empl> lstSource = new List<empl>();

        lstSource.Add(new empl { departmentId = 2, Id = 101, Name = "S1" }); 
        lstSource.Add(new empl { departmentId = 2, Id = 109, Name = "S9" });
        lstSource.Add(new empl { departmentId = 2, Id = 102, Name = "S2" });
        

        lstSource.Add(new empl { departmentId = 4, Id = 101, Name = "S1" });
        lstSource.Add(new empl { departmentId = 4, Id = 102, Name = "S2" });
        lstSource.Add(new empl { departmentId = 4, Id = 108, Name = "S8" });

        lstSource.Add(new empl { departmentId = 3, Id = 105, Name = "S5" });
        lstSource.Add(new empl { departmentId = 3, Id = 103, Name = "S3" });
        lstSource.Add(new empl { departmentId = 3, Id = 102, Name = "S2" });

should result {Id = 102, Name = "S2"} if I add

lstSource.Add(new empl { departmentId = 3, Id = 101, Name = "S1" }); 

should result {Id = 102, Name = "S2"} {Id = 101, Name = "S1"}

Hint : we can group with departmentId and find common Id in 3 group.

Upvotes: 0

Views: 332

Answers (2)

Astrid E.
Astrid E.

Reputation: 2872

Based on your comments and example above, I take it that the Name associated with any given Id is always the same. In that case, you could split the Ids registered on each department into separate lists, then intersect those lists to find the common Ids, and then find the associated Name for each common Id.

You have done something similar in your own example. By rewriting the code (e.g. by replacing the foreach loop with an Aggregate() function) you could achieve a more straight forward approach:

var idsPerDepartment = lstSource
    .GroupBy(item => item.departmentId)
    .Select(gr => gr.Select(item => item.Id));

var commonIds = idsPerDepartment
    .Aggregate((common, next) => common.Intersect(next));

var commonItems = commonIds
    .Select(id => lstSource.First(item => item.Id == id))
    .Select(commonItem => new { commonItem.Id, commonItem.Name })
    .OrderByDescending(commonItem => commonItem.Name);

commonItems is empty (not null) if there are no common items.

It could all be written as one single expression, but I've spilt it into several variables to clarify what is happening along the way.

Upvotes: 1

Anish Sinha
Anish Sinha

Reputation: 139

var groups = lstSource.GroupBy(t1=> t1.departmentId)
                     .ToList();
        var validIds = groups.First().Select(t1 => t1.Id).ToList();
        foreach (var g in groups.Skip(0))
        {
            var otherGroupItemIds = g.Select(t1 => t1.Id).ToList();
            validIds = validIds.Intersect(otherGroupItemIds).ToList();
           
        }
if (validSRIds.Count > 0)
                return lstSource.FindAll(t1 => validSRIds.Contains(t1.Id)).GroupBy(t2 => new { t2.Id, t2.Name }).Select(g => g.First()).OrderByDescending(t => t.Name).ToList();

you will get all common id,name which belongs to all group

Upvotes: 0

Related Questions