-1

Does C# offer a way to create a list directly from an array without copying elements one-by-one?

I know that under-the-hood a list simply maintains an array, so it seems natural to start with an array and make a new list simply point to the array internally. The benefit of this would be tremendous gains in performance when converting array to List.

Is there a native way to do this in c#? If not, does anyone have an extension method or library to do this?

Peter asked for quantification of "tremendous gains in performance". So here it is based on my understanding of how List constructor works:

List() contains three overloads. One of the overloads takes IEnumerable as input. This overload works by declaring a new list of very small size (unless it has changed in a more recent build of c#, the historical default size is 0 and then initialized to 4 when an element is first added).

Each time an element is added to the the list, if the new element exceeds the capacity, then the array size is doubled by creating an entirely new array and copy elements one by one to the new array. The result of this is that the cost of building a List from an IEnumerable is O(n) PLUS the cost of all the array copies that occur. Point being, it's not small.

In the case of an IEnumerable, the List() construction must work this way because IEnumerable is of unknown size. If you were making a List from an array, you would know the exact size at creation time, which means the cost should be O(1).

JamesHoux
  • 2,999
  • 3
  • 32
  • 50
  • 2
    Please quantify the "tremendous gains in performance". Seems like premature optimization for most cases. – Peter B Sep 25 '18 at 18:57
  • You may or may not be thinking about [`Span`](https://msdn.microsoft.com/en-us/magazine/mt814808.aspx). – GSerg Sep 25 '18 at 18:58
  • 2
    the List constructor that takes an array will call Array.Copy. That I suspect will blit the entire array rather than enumerating and copying one by one. – pm100 Sep 25 '18 at 19:01
  • 1
    If you are willing to do some performance testing, you may find that something like `var newList = new List(theArray.Length); newList.AddRange(theArray);` is somewhat faster (though, who knows, that might be what `System.Array.ToList` does under the covers – Flydog57 Sep 25 '18 at 19:02
  • 1
    I'm slightly confused by the question -- whether the `List` constructor copies items *one by one* is an implementation detail. When given an array as an argument, the list constructor calls `CopyTo` from the old array to the new array, as well it should. How `CopyTo` works -- whether it copies items one at a time, or batches them up to take advantage of the processor's ability to copy multiple small items at the same time -- is again, an implementation detail. But that code should be *very fast*. – Eric Lippert Sep 25 '18 at 19:03
  • Is converting an array to a list an operation that you need to be sublinear? If so, then **why is the data in an array in the first place?** Surely the right thing to do is to avoid the copy, not to have some dangerous scheme whereby someone has a reference to an interior implementation detail of a commonly used data structure. – Eric Lippert Sep 25 '18 at 19:05
  • Possible duplicate of [C# copy values from array to list](https://stackoverflow.com/questions/26795897/c-sharp-copy-values-from-array-to-list) – Siavash Sep 25 '18 at 19:07
  • @Eric Lippert That's a good point. I've been contemplating moving away from using arrays for that very reason and using Lists almost exclusively. I've seen some people in the Software Engineering community take the opinion that arrays imply a level of immutability versus Lists (and I myself was somewhat erroneously following that view). The truth is that arrays only imply Fixed length and Lists even have support for Read-Only and Fixed-Length. Considering that Lists are only marginally slower than arrays, I've been moving away from arrays. That lead to this silly question. – JamesHoux Sep 25 '18 at 19:19
  • 1
    I don't think it is a silly question; I do think that arrays are almost never the data structure that meets my needs, for exactly the reasons you cite! Arrays are this weird combination of fixed-in-size-but-mutable-in-contents which I don't want. I wrote a blog article a decade ago about this very subject. https://blogs.msdn.microsoft.com/ericlippert/2008/09/22/arrays-considered-somewhat-harmful/ – Eric Lippert Sep 25 '18 at 19:36

2 Answers2

5

No, because the List object needs to be able to count on having control of the array. If you have a reference to the array outside of the List, it loses that guarantee.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1
  1. You probably don't need the extra performance, and if your app is experiencing performance issues, converting from arrays to lists likely isn't the culprit.
  2. If it is the culprit, and if you do need the performance, you should first attempt to refactor your code so that you don't need to convert from Arrays to Lists as often.
  3. In the very unlikely case that you really do need it, and if you're really ambitions, you may be able to make your own IList<T> and add your array to that.

So what you'd have is something like

public class CustomList<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    public CustomList (T[] array)
    {
        //insert implementation here
    }
    // insert implimentation here
}

note: the supposed performance gain you get from doing this probably isn't worth the time it takes to implement this class, not to mention the risk that you make some mistakes implementing the new List. If you have to ask a question like this on Stack Overflow, you probably aren't experienced enough to make a better IList<T> than Microsoft.