0

I want to check if an enumeration contains 0, 1 or 1+ elements. I want to avoid the overhead of enumerating the entire sequence, thus want to avoid Count().

I know Linq query SingleOrDefault() could be used for this purpose, but instead adds cumbersome exception handling in the 1+ case.

Any way to do it without Count() and without exception handling?

Kjell Rilbe
  • 1,331
  • 14
  • 39
  • *Don't* use Single then, use `First` – Panagiotis Kanavos Aug 19 '16 at 10:42
  • 1
    You can just use `Count` – Adil Mammadov Aug 19 '16 at 10:42
  • You ask if it contains *multiple* elements and you complain that `Single` or `SingleOrDefault` will throw an exception. The odd thing is that these two methods, though throwing exceptions, *doesn't do what you say you want to do*. Can you clarify what the question really is? Do you want to get the first element, check if it contains 1 element, at least 2? – Lasse V. Karlsen Aug 19 '16 at 10:45
  • Sorry. Added clarification about avodiing Count because it will enumerate the entire sequence. – Kjell Rilbe Aug 19 '16 at 10:45
  • I want to check if the enumeration contains 0, 1 or 1+ elements without using Count (to avoid the overhead of enumerating the entire sequence). Will clarify question text. – Kjell Rilbe Aug 19 '16 at 10:46
  • Do you want to obtain these 3 results *at the same time* without enumerating even the start of the collection more than once? Also, do you want the first item as a value if it exists? I'm just trying to avoid posting an answer only to have you go "Yes, but then how do I ..." immediately. – Lasse V. Karlsen Aug 19 '16 at 10:47
  • You can "classify" the contents of the collection by doing: `collection.Take(2).Count()` which will return 0, 1 or 2 (2 thus means 1+ elements). Would that be enough? – Lasse V. Karlsen Aug 19 '16 at 10:50
  • @LasseV.Karlsen: Yes, Take(2).Count() would be alright. I will use the result to choose code path below, and in the 1+ branch will enumerate the entire sequence or (in some cases) throw an exception with custom message text. With SingleOrDefault I would need to catch and rethrow to insert my specific message, which seems overly complex. – Kjell Rilbe Aug 19 '16 at 10:53
  • 1
    Note that this code would enumerate over the start of the collection, and your following enumeration would enumerate it again. If you need/want to avoid that, having 1 enumeration **in total**, then the code needs to be specifically written to do this. – Lasse V. Karlsen Aug 19 '16 at 10:55

4 Answers4

4

One approach to see if the sequence has more than one element is to use Take and Count, like this:

if (mySequence.Take(2).Count() == 2) {
    ... // Sequence has at least two elements
}

Take(2) limits counting to at most two, so using Count() is not as expensive as in mySequence.Count() > 1.

If you need to grab the first element, store the result of Take in a list to avoid iterating the sequence again.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2
.ElementatOrdefault(1) != null
Gilad Green
  • 36,708
  • 7
  • 61
  • 95
Slai
  • 22,144
  • 5
  • 45
  • 53
  • Nice, but I think Take(n).Count() is a bit clearer, with no significant difference in enumeration handling/overhead. – Kjell Rilbe Aug 19 '16 at 10:59
2

You can use skip and any.

list.Skip(n).Any();
  • Nice, but I think Take(n).Count() is a bit clearer, with no significant difference in enumeration handling/overhead. – Kjell Rilbe Aug 19 '16 at 10:59
0

If you want to return the first element that matches some criteria, you should use First or FirstOrDefault, not Single

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236