我在C#中有一个List<List<string>>
-父级列表中的项数会有所不同-可能是1或可能是5。在考虑所有值时,我需要知道是否有重复项在所有列表中处于相同位置。
这类似于对复合键的数据库唯一约束,在复合键中不能重复。每个列表都包含表中数据的所有值。
例如,如果我具有以下结构(但每个结构只能有1列或更多列):
Product Color Size
Tshirt Blue S
Tshirt Blue M
Tshirt Blue L
Tshirt Blue S <-- this is a duplicate
Tshirt Red S
应该是
var items = new List<List<string>>()
{
new List<string>() { "Tshirt", "Tshirt", "Tshirt", "Tshirt", "Tshirt", },
new List<string>() { "Blue", "Blue", "Blue", "Blue", "Red", },
new List<string>() { "S", "M", "L", "S", "S", },
};
我需要检测是否存在重复项,并将重复项打印为
Duplicate: Tshirt, Blue, S
注意:按引用的“重复项”中的说明在单个列表中查找重复项很容易,如果列表是静态的,则可以查找重复项,但这是不同的,因为大小完全未知。它实际上可能是一个List<List<string>>
,具有0个元素,1个或更多元素。
答案 0 :(得分:4)
尝试一下:
var items = new List<List<string>>()
{
new List<string>() { "Tshirt", "Tshirt", "Tshirt", "Tshirt", "Tshirt", },
new List<string>() { "Blue", "Blue", "Blue", "Blue", "Red", },
new List<string>() { "S", "M", "L", "S", "S", },
};
var duplicates =
Enumerable
.Range(0, items.First().Count)
.Select(x => new { Product = items[0][x], Color = items[1][x], Size = items[2][x], })
.GroupBy(x => x)
.SelectMany(x => x.Skip(1).Take(1))
.ToArray();
给出:
鉴于需要处理可变数量的内部列表,以下是处理方法:
var duplicates =
Enumerable
.Range(0, items.First().Count)
.Select(x => Enumerable.Range(0, items.Count).Select(y => items[y][x]).ToArray())
.GroupBy(x => String.Join("|", x))
.SelectMany(x => x.Skip(1).Take(1))
.ToArray();
给出:
这是不使用Count
的惰性版本:
var duplicates =
items
.Select(xs => xs.Select(y => Enumerable.Repeat(y, 1)))
.Aggregate((z0s, z1s) => z0s.Zip(z1s, (z0, z1) => z0.Concat(z1)))
.GroupBy(ws => String.Join("|", ws))
.SelectMany(gws => gws.Skip(1).Take(1));
答案 1 :(得分:1)
您可以使用Zip()
和Aggregate()
LINQ方法在List<List<string>>
(甚至List<List<object>>
)中查找重复项:
string separator = ";%;*;%;"; // Pick a string that's very unlikely to appear in results
var duplicates = items.Aggregate((currentList, nextList) =>
currentList.Zip(nextList, (currentListItem, nextListItem) =>
$"{currentListItem}{separator}{nextListItem}").ToList())
.GroupBy(item => item).Where(group => group.Count() > 1)
.Select(item => item.Key.Split(new[] { separator }, StringSplitOptions.None)
.ToList())
.ToList();
Aggregate()方法将有效地遍历外部列表,一次考虑2个内部列表。然后可以将这些列表逐项Zip合并在一起,以产生新的IEnumerable<string>
;必须进行ToList()
调用,因为这个新的IEnumerable<string>
成为Aggregate()
方法的下一个输入,并且必须与下一个List<string>
将所有内部List<string>
压缩到新的IEnumerable<string>
中后,其中的项目将与分隔符连接在一起(对于使用分隔符非常重要,以避免对重复匹配产生误报,例如{ {1}}),您只需"aa" + "abb" == "aaa" + "bb"
个项目,然后找到包含1个以上项目的任何组。
最后,最后一个GroupBy()
将结果转换回Select()
格式,以便与原始数据轻松比较。
此解决方案完全是LINQ(您甚至可以将List<List<string>>
直接硬编码到查询中),并且适用于任意数量的内部列表(仅包括1个列表)。