Dan*_*ues -3 c# linq union select
编辑:为什么 Union() 没有像它应该的那样排除重复项?
在提出原始问题之前,我应该阅读文档。我没有,因为每次我使用 Union() 时都是在没有覆盖 Equals() 和 GetHashCode() 的对象列表上,所以即使列表中每个对象的字段值相同,它们将在创建的新列表 Union() 内。起初,似乎 Union() 没有排除重复项,而我认为这是真的。但实际上, Union() 确实排除了重复项。不仅在两个列表中重复,而且在同一个列表中也重复。如果我的对象不覆盖 Equals() 和 GetHashCode() 它们不会按值进行比较,这意味着它们看起来不是重复的。
这是让我问这个问题的困惑。
一旦我使用 Union() 和 Select() 显式地创建了一个新列表,“T”将成为一个匿名类型,按值进行比较。这样,具有相同字段值的对象将被视为重复。这就是导致 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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我运行以下程序:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
预期的输出是:
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.
Run Code Online (Sandbox Code Playgroud)
但实际输出是:
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.
Run Code Online (Sandbox Code Playgroud)
请注意,第一个列表包含两个具有相同值的提取。球的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));
Run Code Online (Sandbox Code Playgroud)
因此,似乎在 Union() 之后使用的“选择”正在从第一个列表中删除重复项。
真正的问题是,我实际上没有像示例中那样的简单类型列表,但我有一个 IEnumerable< T > 列表(T 是匿名类型)并且 T 有很多字段。我只想要特定的字段,但我想要所有新的匿名类型重复项。我发现的唯一解决方法是,如果在 'Select()' 中添加一些对每个对象 T 都是唯一的字段。
这是否按预期工作?Union + Select 应该删除重复项吗?
是的,这是预期的行为。
联盟的文件状态
返回值 类型:System.Collections.Generic.IEnumerable 一个 IEnumerable,包含来自两个输入序列的元素,不包括重复项。
要保留重复项,您必须使用Concat(),而不是Union()