E.Beach
E.Beach

Reputation: 1857

Efficient Linq Enumerable's 'Count() == 1' test

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?

Upvotes: 32

Views: 5548

Answers (7)

3dGrabber
3dGrabber

Reputation: 5074

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.

Upvotes: 4

juFo
juFo

Reputation: 18567

bool hasTwo = yourSequence.ElementAtOrDefault(1) != default(T);

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

Upvotes: 0

phoog
phoog

Reputation: 43046

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!

Upvotes: 1

Paul Ruane
Paul Ruane

Reputation: 38590

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‽");
    }
}

Upvotes: 11

CodeNaked
CodeNaked

Reputation: 41393

Another way:

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

Or for exactly 1 element:

bool containsOneElement = yourSequence.Any() && !yourSequence.Skip(1).Any();

Upvotes: 9

JaredPar
JaredPar

Reputation: 754685

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();
  }
}

Upvotes: 17

LukeH
LukeH

Reputation: 269368

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

Upvotes: 69

Related Questions