首页 > 解决方案 > 如何在 linq 的动态列表中查找重复项?

问题描述

List<List<string>>在 C# 中有一个 - 父列表中的项目数会有所不同 - 可能有 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 个或更多元素的 a。

标签: c#linq

解决方案


试一试:

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();

这给出了:

重复2


这是一个不使用的惰性版本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));

推荐阅读