[英]C# Why does Except and Where Enumerable Give This Weird Result?
我一直在調試這個生產錯誤,我迫切需要幫助,這對我來說也很有意思。
我簡化了代碼邏輯並為調試添加了一些打印輸出:
int[] a = { 2,2,2 };
var b = a.Where(x => x==2);
for(int i = 0; i < 3; i++)
{
var c = b.Where(x => x==i);
Console.WriteLine("iter {0} before - B Count: {1}, C Count: {2}", i, b.Count(), c.Count());
if (c.Count() != b.Count())
b = b.Except(c);
Console.WriteLine("iter {0} after - B Count: {1}, C Count: {2}", i, b.Count(), c.Count());
}
Console.WriteLine("After Loop: B Count: {0}", b.Count());
有趣的是(奇怪),輸出是:
iter 0 before - B Count: 3, C Count: 0
iter 0 after - B Count: 1, C Count: 0
iter 1 before - B Count: 1, C Count: 0
iter 1 after - B Count: 1, C Count: 0
iter 2 before - B Count: 0, C Count: 0
iter 2 after - B Count: 0, C Count: 0
After Loop: B Count: 1
為什么b.Count() == 0
at“iter 2 before”。 唯一的事情發生在“iter 1 after和iter 2 before”之間
var c = b.Where(x => x==i);
為什么這個代碼會改變b?
為什么b.Count()
在循環結束后變回1?
我非常感謝大家的幫助,指導我解決這個問題,謝謝!
由於linq的惰性求值,每次調用Count()
時都會執行Where
和Except
調用。 這里需要注意的重要一點是, i
的值不會被記住,而是將所有先前Where
調用的當前值取為i
。
為什么b.Count()== 0 at“iter 2 before”
此時, i
已經增加到2
。 當您調用count時,將使用此值評估整個linq查詢,這意味着之前添加的“Except”調用已經刪除了所有內容!
為什么b.Count()在循環結束后變回1?
當i
等於3時,循環結束。現在當你評估整個linq查詢時, .Where(x => x==i)
調用都不會返回任何內容,這反過來意味着沒有任何Except
調用會刪除任何東西(除了重復之外)。
對於1 :“為什么這個代碼會改變b?”
它沒有。 添加(在循環開始時,在c
之前):
Console.WriteLine("iter {0} before anything - B Count: {1}", i, b.Count());
b
沒有變化。
2 :那是因為被捕獲的i
。 改成:
for(int tmp = 0 ; tmp < 3 ; tmp++) {
int i = tmp;
// ...
}
然后再試一次。 現在i
的作用域確定在循環內 ,並且相應地捕捉(在該迭代變量for
循環的作用域確定的循環外 ,對於復雜的原因;在一個foreach
循環中,迭代變量是僅限內部或外循環依賴於你正在使用的C#版本)
像它的SQL對應的行為Except
,它消除了重復。 因此,它的行為就像在列表中調用Distinct
。
所以當你第一次執行Except
if (c.Count() != b.Count()) // c.Count() == 0, b.Count() == 3
b = b.Except(c);
您只能獲得b
的唯一元素,其中只有一個元素。
Enumerable.Except
通過使用默認的相等比較器來比較值來產生兩個序列的集合差異。 集合不包含重復項。
這就是為什么序列在Except
之后只包含一個2。
int[] onlyOneTwo = new[]{ 2,2,2 }.Except(Enumerable.Empty<int>()).ToArray();
所以Except
使用一個集合 Except
,空序列不會刪除任何內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.