有没有办法在 C# 中的分组列表中查找公共元素?
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" });
结果应该是 {Id = 102, Name = "S2"}
如果我添加
lstSource.Add(new empl { departmentId = 3, Id = 101, Name = "S1" });
结果应该是 {Id = 102, Name = "S2"} {Id = 101, Name = "S1"}
提示:我们可以用 departmentId 分组,并在 3 组中找到共同的 Id。
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();
你会得到属于所有组的所有公共id,name
根据您的评论和上面的示例,我认为与任何给定 Id
关联的 Name
始终相同。在这种情况下,您可以将每个部门注册的 Id
拆分为单独的列表,然后将这些列表相交以找到共同的 Id
,然后为每个共同的找到关联的 Name
Id
.
你在你自己的例子中做了类似的事情。通过重写代码(例如,将 foreach
循环替换为 Aggregate()
函数),您可以获得更直接的方法:
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
为空(不是 null
)。
它可以全部写成一个单独的表达式,但我将它分解成几个变量以阐明过程中发生的事情。
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" });
结果应该是 {Id = 102, Name = "S2"} 如果我添加
lstSource.Add(new empl { departmentId = 3, Id = 101, Name = "S1" });
结果应该是 {Id = 102, Name = "S2"} {Id = 101, Name = "S1"}
提示:我们可以用 departmentId 分组,并在 3 组中找到共同的 Id。
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();
你会得到属于所有组的所有公共id,name
根据您的评论和上面的示例,我认为与任何给定 Id
关联的 Name
始终相同。在这种情况下,您可以将每个部门注册的 Id
拆分为单独的列表,然后将这些列表相交以找到共同的 Id
,然后为每个共同的找到关联的 Name
Id
.
你在你自己的例子中做了类似的事情。通过重写代码(例如,将 foreach
循环替换为 Aggregate()
函数),您可以获得更直接的方法:
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
为空(不是 null
)。
它可以全部写成一个单独的表达式,但我将它分解成几个变量以阐明过程中发生的事情。