快速提问,编程问题的首选方法是什么?“此序列中是否只有一个元素满足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方法?
答案 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;
}
}
}