[英]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.