开发者

Cheapest way to copy an IEnumerable<T>?

I've got an IEnumerable<T>, and I need a copy of it. Anything that implements IEnumerable<T> will do just fine. What's the cheapest way to copy it? .T开发者_Go百科oArray() maybe?


ToArray is not necessarily faster than ToList. Just use ToList.

The point is as long as you don't know the number of elements of the original sequence before enumerating, you end up with resizing an array and adding elements to it like a List<T> does, so ToArray will have to do the same thing a List<T> does anyway. Besides, ToList gives you a List<T> and that's nicer than a raw array.

Of course, if you know the concrete type of the IEnumerable<T> instance, there can be faster methods, but that's not germane to the point.

Side note: using an array (unless you have to) is arguably a micro-optimization and should be avoided most of the time.


Enumerable::ToArray and Enumerable::ToList ultimately use the same technique to receive elements from the source into an internal array buffer and, once the size of that buffer is reached, they will allocate a new buffer double the size, memcpy over and continue adding elements, repeating this process until enumeration over the source is complete. The difference in the end is that ToArray, which uses a Buffer<T> implementation internally, must then allocate an exactly sized Array and copy the elements into it before returning the result. On the other hand, ToList just needs to return the List<T> with a potentially (likely) only partially filled array buffer inside of it.

Both implementations also have an optimization where if the source IEnumerable is an ICollection they will actually allocate the exact right buffer size to begin with using ICollection::Count and then use ICollection::CopyTo from the source to fill their buffers.

In the end you will find that they perform nearly identically in most situations, but the List<T> is technically a "heavier" class to hang on to in the end and the ToArray has that extra allocate + memcpy at the end (if the source isn't an ICollection) to be able to hand back the exactly right sized array. I usually stick with ToList myself unless I know I need to pass the result to something that requires an array like say maybe Task::WaitAll.


I was about to suggest the possibility of using .AsParallel().ToList() if you have TPL at your disposal, but informal testing on my dual-core laptop shows it to be 7x slower than just .ToList(). So, stick with Mehrdad's answer.


The second-to-cheapest way is to say new List<T>(myEnumerable).ToArray(). The cheapest way is to use either .ToArray() (from LINQ) or, if you don't have C# 3.5, to create your own buffer and add to it while doubling its size, then trim it at the end.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜