[英]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 应该删除重复项吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.