2010-01-02 28 views
10

快速的問題,programmaticaly最好的方法是問「這個序列中是否只有一個元素滿足X條件?」使用Linq?如何在LINQ中問「在LINQ中有沒有滿足條件的元素?

// Pretend that the .OneAndOnlyOne() method exists 
int[] sequence = new int[] { 1, 1, 2, 3, 5, 8 }; 
Assert.IsTrue(sequence.OneAndOnlyOne(x => x == 2); 
Assert.IsFalse(sequence.OneAndOnlyOne(x => x == 1); 

這樣的事情可以做:

sequence.SingleOrDefault(x => x == 2) != null; 

但是這是一個有點麻煩。

我想我可以推出自己的擴展方法,但這似乎是我的代碼中的一種常見模式,我想確保有一個很好的乾淨方法來做到這一點。有沒有使用內置LINQ方法的方法?

+0

'SingleOrDefault'將引發InvalidOperationException :如果有多個比賽。 – SLaks 2010-01-02 23:32:56

+0

我推薦IsLone()作爲擴展方法的可能替代名稱。你也用同樣的功能做兩件事,過濾然後檢測是否只有一個元素。我會這樣做:sequence.Where(x => x == 2).IsLone() – ICR 2010-01-03 01:39:00

回答

29

讓你可以做什麼:

bool onlyOne = source.Where(/*condition*/).Take(2).Count() == 1 

,這將阻止在發生多次匹配時計算不必要的大量序列。

+0

+1,我希望我可以給你另外一個+1。'Take(2)'部分(這非常合理。) – 2010-01-03 00:11:22

+0

嘿,我有點像。我可能會在我自己的擴展方法後面加上別名。 – Mike 2010-01-03 00:21:14

+0

你爲什麼拿2個元素?這背後有什麼意義? ;) – citronas 2010-01-03 00:30:40

2

最簡單的方法就是使用Count。 Single不會爲你工作,因爲如果不只有那個單一元素,它會拋出一個異常。

LBushkin建議(在評論中)使用SequenceEqual來比較序列與另一個序列。你可以使用,通過跳過與跳過(1)第一個元素,並比較結果序列爲空序列,例如你可以從Empty

+2

是的,但是如果我的.OneAndOnlyOne()方法在一個序列上運行,並擊中滿足謂詞的第二個元素 - 它可以返回錯誤的權利遠。 Count()將枚舉整個序列 – Mike 2010-01-02 23:35:12

+0

這是事實,但是「超出」Count可能是過早優化的情況 - 當然,取決於您的需要。如果你想防止這種情況,你可以使用.Skip(1),看看你是否得到一個空序列。 – 2010-01-02 23:38:11

+0

@Michael:你不需要使用Count。你可以使用'SequenceEqual()'來處理空序列,而不會拋出異常。而且,您可以隨時推出自己的擴展方法......並不是OP對於使用情況來說非常必要。 – LBushkin 2010-01-02 23:52:00

0

你可以使用這個擴展方法,我認爲應該已經包含在標準的擴展方法LINQ:

public static int CountUpTo<T>(this IEnumerable<T> sequence, int maxCount) { 
    if (sequence == null) throw new ArgumentNullException("sequence"); 
    if (maxCount < 0) throw new ArgumentOutOfRangeException("maxCount"); 

    var count = 0; 
    var enumerator = sequence.GetEnumerator(); 
    while (count < maxCount && enumerator.MoveNext()) 
     count += 1; 
    return count; 
} 

使用像這樣:

return sequence.CountUpTo(2) == 1; 
相關問題