如何在LINQ中询问“是否只有一个满足条件的元素”?

时间:2010-01-02 23:25:43

标签: c# .net linq

快速提问,编程问题的首选方法是什么?“此序列中是否只有一个元素满足X条件?”使用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方法?

4 个答案:

答案 0 :(得分:34)

你可以这样做:

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

这会阻止count在多次匹配时不必要地枚举大序列。

答案 1 :(得分:5)

最简单的方法是使用Count。 Single不适合你,因为如果没有单个元素,它会引发异常。

LBushkin建议(在评论中)使用SequenceEqual来比较序列与另一个序列。您可以通过使用Skip(1)跳过第一个元素,并将结果序列与空序列(例如您可以从Empty获得的内容

进行比较来使用它

答案 2 :(得分:1)

你可以使用这个扩展方法,我认为它应该包含在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;

答案 3 :(得分:0)

一旦我遇到问题来确定是否仅包含一项,便决定创建以下扩展名。在我的选择中,它非常适合现有的扩展集(例如:SingleOrDefualt,FirstOrDefault ...)。

 public static class IEnumerableExtension
{
    public static TProject OneOrDefault<TInput, TProject>(this IEnumerable<TInput> sequence, Func<TInput, TProject> projection)
    {
        var enumerator = sequence.GetEnumerator();
        bool firstMoveNext = enumerator.MoveNext();
        TInput current = enumerator.Current;
        if (firstMoveNext && !enumerator.MoveNext())
        {
            return projection(current);
        }
        else
        {
            return default;
        }
    }
}