11

I have this method (simplified):

void DoSomething(IEnumerable<int> numbers);

And I invoke it like this:

DoSomething(condition==true?results:new List<int>());

The variable results is formed with a LINQ select condition (IEnumerable).

I was wondering is this List<int>() the best way (the fastest?) to pass an empty collection, or is new int[0] better? Or, something else would be faster, a Collection, etc.? In my example null wouldn't be ok.

avance70
  • 787
  • 1
  • 11
  • 22

2 Answers2

31

I'd use Enumerable.Empty<int>()

DoSometing(condition ? results : Enumerable.Empty<int>());
Lee
  • 142,018
  • 20
  • 234
  • 287
  • 1
    From a performance perspective, `Enumerable.Empty` will be (slightly) faster than creating a new array, because the calling the `GetEnumerator()` on the `EmptyEnumerable` will return itself, while calling `GetEnumerator()` on array, will create a new object. Of course this would be a micro optimization. `Enumerable.Empty` is just more readable :-) – Steven May 05 '10 at 13:31
  • This is probably a question for an other thread, but what's the best way to create an IEnumerable with just 1 integer value? – avance70 May 05 '10 at 13:37
  • @avance70: Do you care if the resulting sequence is mutable? The problem with a single-element array is that someone can then *change* the contents of it. – Eric Lippert May 05 '10 at 14:23
1

@avance70. Not really an answer to original question, but a response to avance70's question about an IEnumerable with just 1 integer value. Would have added it as a comment, but I don't have enough rep to add a comment. If you are interested in a strictly immutable sequence, you have a couple of options:

Generic extension method:

public static IEnumerable<T> ToEnumerable<T>(this T item)
{
  yield return item;
}

Use like this:

foreach (int i in 10.ToEnumerable())
{
  Debug.WriteLine(i); //Will print "10" to output window
}

or this:

int x = 10;
foreach (int i in x.ToEnumerable())
{
  Debug.WriteLine(i); //Will print value of i to output window
}

or this:

int start = 0;
int end = 100;
IEnumerable<int> seq = GetRandomNumbersBetweenOneAndNinetyNineInclusive();

foreach (int i in start.ToEnumerable().Concat(seq).Concat(end.ToEnumerable()))
{
  //Do something with the random numbers, bookended by 0 and 100
}

I recently had a case like the start/end example above where I had to "extract" consecutive values from a sequence (using Skip and Take) and then prepend and append start and end values. The start and end values were interpolated between the last not-extracted value and the first extracted value (for start) and between the last extracted value and the first non-extracted value (for end). The resulting sequence was then operated on again, possibly reversing.

So, if original sequence looked like:

1 2 3 4 5

I might have to extract 3 and 4 and add interpolated values between 2 and 3 and 4 and 5:

2.5 3 4 4.5

Enumerable.Repeat. Use like this:

foreach (int i in Enumerable.Repeat(10,1)) //Repeat "10" 1 time.
{
  DoSomethingWithIt(i);
}

Of course, since these are IEnumerables, they can also be used in conjunction with other IEnumerable operations. Not sure if these are really "good" ideas or not, but they should get the job done.

wageoghe
  • 27,390
  • 13
  • 88
  • 116