32

Similar to this question but rephrased for Linq:

You can use Enumerable<T>.Any() to test if the enumerable contains data. But what's the efficient way to test if the enumerable contains a single value (i.e. Enumerable<T>.Count() == 1) or greater than a single value (i.e. Enumerable<T>.Count() > 1) without using an expensive count operation?

Community
  • 1
  • 1
E.Beach
  • 1,829
  • 2
  • 22
  • 34

7 Answers7

68
int constrainedCount = yourSequence.Take(2).Count();

// if constrainedCount == 0 then the sequence is empty
// if constrainedCount == 1 then the sequence contains a single element
// if constrainedCount == 2 then the sequence has more than one element
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 2
    make sure you don't work with the yourSequence data itself because skipping or taking might lose/comsume the data in some cases. it is ok if you are only concerned about the count. – juFo Jan 07 '19 at 10:09
17

One way is to write a new extension method

public static bool IsSingle<T>(this IEnumerable<T> enumerable) {
  using (var enumerator = enumerable.GetEnumerator()) {
    if (!enumerator.MoveNext()) {
      return false;
    }
    return !enumerator.MoveNext();
  }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 2
    @CodeArtist One measurement is worthless. You need to calculate an average and standard deviation. On my machine the difference is meaningless. – BartoszKP Mar 21 '17 at 10:11
11

This code take's LukeH's excellent answer and wraps it up as an IEnumerable extension so that your code can deal in terms of None, One and Many rather than 0, 1 and 2.

public enum Multiplicity
{
    None,
    One,
    Many,
}

In a static class, e.g. EnumerableExtensions:

public static Multiplicity Multiplicity<TElement>(this IEnumerable<TElement> @this)
{
    switch (@this.Take(2).Count())
    {
        case 0: return General.Multiplicity.None;
        case 1: return General.Multiplicity.One;
        case 2: return General.Multiplicity.Many;
        default: throw new Exception("WTF‽");
    }
}
Paul Ruane
  • 37,459
  • 12
  • 63
  • 82
9

Another way:

bool containsMoreThanOneElement = yourSequence.Skip(1).Any();

Or for exactly 1 element:

bool containsOneElement = yourSequence.Any() && !yourSequence.Skip(1).Any();
CodeNaked
  • 40,753
  • 6
  • 122
  • 148
4

Efficient Count() == n test:

public static bool CountIsEqualTo<T>(this IEnumerable<T> enumerable, int c) 
{
    using (var enumerator = enumerable.GetEnumerator()) 
    {
        for(var i = 0; i < c ; i++)
            if (!enumerator.MoveNext()) 
                return false;
        
        return !enumerator.MoveNext();
    }
}

Edit, 11 years later:
Nowadays I'd probably write this as

public static bool CountIsEqualTo<T>(this IEnumerable<T> enumerable, int c) 
{
    return enumerable.Take(c + 1).Count() == c;
}

It's a generalized version of the accepted answer.

3dGrabber
  • 4,710
  • 1
  • 34
  • 42
1

With linq to objects, SingleOrDefault throws if there is more than one element, so you're probably best off if you roll your own.

EDIT: Now I've seen LukeH's answer, and I have to say I prefer it. Wish I'd thought of it myself!

Paul Fleming
  • 24,238
  • 8
  • 76
  • 113
phoog
  • 42,068
  • 6
  • 79
  • 117
  • Single() throws - SingleOrDefault() will return the default value for the generic type (null for reference types). – David Neale May 19 '11 at 14:01
  • 3
    @David: Nope, `SingleOrDefault` will throw if there is more than one element. It only returns `default(T)` if there are no elements. – LukeH May 19 '11 at 14:04
  • 3
    @David, his comment about `SingleOrDefault` is true. The difference between `Single` and `SingleOrDefault` is not whether they throw, only when. – Anthony Pegram May 19 '11 at 14:04
0
bool hasTwo = yourSequence.ElementAtOrDefault(1) != default(T);

...in case of class where values can be null this could maybe we useful.

juFo
  • 17,849
  • 10
  • 105
  • 142