繁体   English   中英

为什么 Union() 没有像它应该的那样排除重复项?

[英]Why is Union() not excluding duplicates like it should?

编辑:为什么 Union() 没有像它应该的那样排除重复项?

在提出原始问题之前,我应该阅读文档。 我没有,因为每次我使用 Union() 时都是在没有覆盖 Equals() 和 GetHashCode() 的对象列表上,所以即使列表中每个对象的字段值相同,它们将在创建的新列表 Union() 内。 起初,似乎 Union() 没有排除重复项,而我认为这是真的。 但实际上, Union() 确实排除了重复项。 不仅在两个列表中重复,而且在同一个列表中也重复。 如果我的对象不覆盖 Equals() 和 GetHashCode() 它们不会按值进行比较,这意味着它们看起来不是重复的。

这是让我问这个问题的困惑。

一旦我使用 Union() 和 Select() 显式地创建了一个新列表,“T”将成为一个匿名类型,按值进行比较。 这样,具有相同字段值的对象将被视为重复。 to behave differently).这就是导致 Union() 表现不同(或者表现不同)的原因。 它总是排除重复项,但并不总是按值比较类型,因此具有相同字段值的对象可能会或可能不会看起来是重复的。 这取决于您的自定义类的实现。

我想这应该是一个问题:为什么 Union() 没有像它应该的那样排除重复项? (正如我们所见,这是因为我的对象并不是真正的重复项)。 那正确吗?

---------------

原始问题: LINQ Union + Select 会自动删除重复项。 为什么?

我一直认为 Linq 中的 Union() 会返回两个列表中的所有值,即使它们相同。 但是当我在 Union() 之后使用“Select()”时,我的代码正在从第一个列表中删除重复项。

想象一下球提取的经典概率问题,我有不同的容器,我从容器中提取一些不同的球。

我有两个 BallExtraction 列表。 每个列表都显示了球的 ID、球所在容器的 ID、我提取的球数(值)及其颜色。 但是,出于某种原因,我有两个不同的列表,我想合并它们。

示例代码:

class BallExtraction
{
    public enum BallColor 
    {
        Blue = 0,
        Red = 1
    } 

    public int Id { get; set; }
    public int IdContainer { get; set; }
    public int ValueExtracted { get; set; }
    public BallColor Color { get; set; }

    public BallExtraction() { }

    public BallExtraction(int id, int idContainer, int valueExtracted, BallColor color)
    {
        this.Id = id;
        this.IdContainer = idContainer;
        this.ValueExtracted = valueExtracted;
        this.Color = color;
    }

}

现在我运行以下程序:

class Program
{
    static void Main(string[] args)
    {
        List<BallExtraction> list1 = new List<BallExtraction>();
        list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Blue));
        list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Blue));
        list1.Add(new BallExtraction(1, 1, 20, BallExtraction.BallColor.Red));
        list1.Add(new BallExtraction(1, 2, 70, BallExtraction.BallColor.Blue));
        list1.Add(new BallExtraction(2, 1, 10, BallExtraction.BallColor.Blue));

        List<BallExtraction> list2 = new List<BallExtraction>();
        list1.Add(new BallExtraction(3, 2, 80, BallExtraction.BallColor.Blue));
        list1.Add(new BallExtraction(3, 2, 80, BallExtraction.BallColor.Red));

        var mergedList = list1.Where(w => w.Color == BallExtraction.BallColor.Blue).Select(s => new
        {
            Id = s.Id,
            IdContainer = s.IdContainer,
            ValueExtracted = s.ValueExtracted
        }).Union(list2.Where(w => w.Color == BallExtraction.BallColor.Blue).Select(s => new
        {
            Id = s.Id,
            IdContainer = s.IdContainer,
            ValueExtracted = s.ValueExtracted
        }));

        Console.WriteLine("Number of items: {0}", mergedList.Count());

        foreach (var item in mergedList)
        {
            Console.WriteLine("Id: {0}. IdContainer: {1}. # of balls extracted: {2}", item.Id, item.IdContainer, item.ValueExtracted);
        }

        Console.ReadLine();

    }
}

预期的输出是:

Number of items: 5
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 2. Value: 70.
Id: 2. IdContainer: 1. Value: 10.
Id: 3. IdContainer: 2. Value: 80.    

但实际输出是:

Number of items: 4
Id: 1. IdContainer: 1. Value: 20.
Id: 1. IdContainer: 2. Value: 70.
Id: 2. IdContainer: 1. Value: 10.
Id: 3. IdContainer: 2. Value: 80.

请注意,第一个列表包含两个具有相同值的提取。 球的Id为1,容器的Id为1,提取的球数为20,均为蓝色。

我发现当我将 'mergedList' 切换到下面的代码时,我得到了预期的输出:

var mergedList = list1.Where(w => w.Color == BallExtraction.BallColor.Blue).Union(list2.Where(w => w.Color == BallExtraction.BallColor.Blue));

因此,似乎在 Union() 之后使用的“选择”正在从第一个列表中删除重复项。

真正的问题是,我实际上没有像示例中那样的简单类型列表,但我有一个 IEnumerable< T > 列表(T 是匿名类型)并且 T 有很多字段。 我只想要特定的字段,但我想要所有新的匿名类型重复项。 我发现的唯一解决方法是,如果在 'Select()' 中添加一些对每个对象 T 都是唯一的字段。

这是否按预期工作? Union + Select 应该删除重复项吗?

是的,这是预期的行为。

联盟的文件状态

返回值 类型:System.Collections.Generic.IEnumerable 一个 IEnumerable,包含来自两个输入序列的元素,不包括重复项

要保留重复项,您必须使用Concat() ,而不是Union()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM