我想要相互独立地捕获重复项,也就是说,我需要显示第一项和第三项都是重复项,第一项和第四项是重复项。
public class Foo
{
public String Name { get; set; }
public String SName { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<Foo>();
list.Add(new Foo { Name = "a", SName = "d" });
list.Add(new Foo { Name = "b", SName = "e" });
list.Add(new Foo { Name = "c", SName = "a" });
list.Add(new Foo { Name = "a", SName = "f" });
// only groups by 1 name
var duplicates = list.GroupBy(i => i.Name).Where(g => g.Count() > 1).Select(g => g.Key);
}
}
我知道这可以用foreach完成,我想学习。
答案 0 :(得分:1)
因此,我们首先从任一列获取所有重复的名称值,这非常简单:
IEnumerable<string> repeatedNames = list.SelectMany(foo => new[] { foo.Name, foo.SName })
.GroupBy(name => name)
.Where (g => g.Count () > 1)
.Select(g => g.Key);
接下来,我们将获取每个名称并查找包含该值的所有项目。最终结果是每个不同名称的序列,其中序列是包含该值的所有Foo
项。
IEnumerable<List<Foo>> groupings = repeatedNames .Select(name =>
list.Where(foo => foo.Name == name || foo.SName == name).ToList());
如果你想要它,而不是一系列Foos列表,一个具有不同值和序列的项目序列,那么它很容易添加:
var groupings = repeatedNames .Select(name => new
{
Name = name,
Foos = list.Where(foo => foo.Name == name || foo.SName == name).ToList()
});
答案 1 :(得分:0)
如果您只想要重复的值而不是它们出现的索引,那么您可以在进行分组之前使用SelectMany
将名称转换为单个字符串列表:
var duplicates2 = list.SelectMany(n => new string[] {n.Name, n.SName})
.GroupBy(g => g)
.Where (g => g.Count () > 1)
.Select(g => g.Key)
.ToList();
修改强>
如果你想要Foo
个对象而不仅仅是字符串,你可以像这样选择它们:
var duplicates3 = list.Where(n => duplicates2.Contains(n.Name) ||
duplicates2.Contains(n.SName));
答案 2 :(得分:0)
我想出了这个:
// Will return "a" - one which you already had
var duplicatesBetweenNames = list.GroupBy(i => i.Name)
.Where(g => g.Count() > 1)
.Select(g => g.Key).ToArray();
var duplicatedInSName = list.Select(x => x.Name)
.Intersect(list.Select(x => x.SName));
// Will return "c" - represents Names where in SName is duplicate
var duplicatesBetweenNameAndSName = list
.Where(f => duplicatedInSName.Contains(f.SName))
.Select(x=>x.Name).ToArray();
答案 3 :(得分:0)
有趣的线程,我只是认为在这种情况下查询语法非常具有表现力:
var r = from l in list
from s in new [] {l.Name,l.SName}
group s by s into g
where g.Count() > 1
select g.Key into u
from l in list
where u.Contains(l.Name) || u.Contains(l.SName)
select l;