32265

copying a list to a new list - More efficient & Best Practice

Question:

What is the appropriate way of copying a list to a new list? And What is the most efficient way of copying a list to a new list?

By efficient, not code efficiency, more in the behind the scenes framework sense.

List<String>List2 = List.ToList();

<strong>Or:</strong>

List<String>List2 = new List<String>(); foreach (string item in List) { List2.Add(item); }

<strong>Update:</strong>

What about more efficient IL code?

Answer1:

What ToList does (shortened):

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { return new List<TSource>(source); }

What List ctor does (shortened):

public List(IEnumerable<T> collection) { ICollection<T> collection2 = collection as ICollection<T>; int count = collection2.Count; this._items = new T[count]; collection2.CopyTo(this._items, 0); this._size = count; }

So the ToList() is much more efficient - it does allocate the space first and then copy all items in one step.

Answer2:

Given that List<T> has an IEnumerable<T> constructor, I would prefer this form:

List<string> newList = new List<string>(otherList);

<strong>Edit</strong>

And as Ondrej points out in the decompiled code below, the constructor of List<T> preallocates the size of the array and copies the contents over. This is going to be much quicker than creating a new list and then iterating over the other list adding items individually, especially as in your 2nd example you're not specifying how many items to preallocate.

Answer3:

You can use <a href="http://msdn.microsoft.com/en-us/library/fkbw11z0%28v=vs.110%29.aspx" rel="nofollow">List<T> constructor</a> that takes IEnumerable<T>

List<string> list1 = new List<string>(); // fill list1 List<string> list2 = new List<string>(list1);

Answer4:

In terms of efficiency, the first is going to be faster. List<T>'s underlying implementation is an ArrayList, so there's a chance you'll have to resize the underlying array when you call .Add.

On the other hand, .ToList can determine the correct initial size of the new List and avoid the reallocation operation that the foreach technique suffers from.

With this in mind I'd recommend .ToList. Less code and it will be faster.

Here's a simple program you can run to verify that ToList is indeed faster:

void Main() { List<int> items = new List<int>(); items = Enumerable.Range(0, 1000000).ToList(); CopyWithToList(items); CopyWithForeach(items); } public void CopyWithToList<T>(List<T> list) { var sw = Stopwatch.StartNew(); List<T> copy = list.ToList(); sw.Stop(); Console.WriteLine("CopyWithToList: {0}", sw.Elapsed); } public void CopyWithForeach<T>(List<T> list) { var sw = Stopwatch.StartNew(); List<T> copy = new List<T>(); foreach (T item in list) { copy.Add(item); } sw.Stop(); Console.WriteLine("CopyWithForeach: {0}", sw.Elapsed); }

Answer5:

I believe that the two examples are identical, the .ToList() implements probably the later.

The best performance would be something like this:

List<String> list2 = new List<String>(list.Count); foreach(String item in list) list2.Add(item);

The important part is to create list2 with enough capacity to hold its content.

If you don't need to modify the either list afterwards, the a reference copy is all you need:

List<String> list2 = list;

Answer6:

Tests shows, that the best perfomance have the .ToList() method (for a list with 21474836 elements it runs in about 48 ms on a laptop Core i5 CPU).

Every other method is slower, and the method, using .Add() is the worst, while talking about perfomance.

Here is some test code:

class Program { static void Main() { var list = new List<int>(); for (int i = 0; i < int.MaxValue / 100; i++) { list.Add(i); } TimeItAccurate(ListCopy_1, list, 10); TimeItAccurate(ListCopy_2, list, 10); TimeItAccurate(ListCopy_3, list, 10); TimeItAccurate(ListCopy_4, list, 10); TimeItAccurate(ListCopy_5, list, 10); } private static List<int> ListCopy_1(List<int> list) { var newList = list.ToList(); return newList; } private static List<int> ListCopy_2(List<int> list) { var newList = new List<int>(list.Count); foreach (var i in list) { newList.Add(i); } return newList; } private static List<int> ListCopy_3(List<int> list) { var newList = new List<int>(list.ToArray()); return newList; } private static List<int> ListCopy_4(List<int> list) { var newList = new List<int>(list.Count); newList.AddRange(list); return newList; } private static List<int> ListCopy_5(List<int> list) { var newList = new List<int>(list); return newList; } public static void TimeItAccurate<TIn, TResult>(Func<TIn, TResult> func, TIn argument, int iterationsCount) { #region Pre-heat for (int i = 0; i < 10; i++) { var t = func.Invoke(argument); } #endregion var stopwatch = new Stopwatch(); var result = default(TResult); stopwatch.Start(); for (int i = 0; i < iterationsCount; i++) { result = func.Invoke(argument); } stopwatch.Stop(); Console.WriteLine("Result:\n{4}(...) == {0}\n\n{1} iterations done in {2} ms.\nAverage time: {3:f5} ms.", result, iterationsCount, stopwatch.ElapsedMilliseconds, stopwatch.ElapsedMilliseconds / (double)iterationsCount, func.Method.Name); } }

And the results:

Result (.ToList()): ListCopy_1(...) == System.Collections.Generic.List`1[System.Int32] 10 iterations done in 474 ms. Average time: 47.40000 ms. Result (for-cycle with .Add()): ListCopy_2(...) == System.Collections.Generic.List`1[System.Int32] 10 iterations done in 1896 ms. Average time: 189.60000 ms. Result (ctor with .ToArray()): ListCopy_3(...) == System.Collections.Generic.List`1[System.Int32] 10 iterations done in 981 ms. Average time: 98.10000 ms. Result (.AddRange()): ListCopy_4(...) == System.Collections.Generic.List`1[System.Int32] 10 iterations done in 959 ms. Average time: 95.90000 ms. Result (new List<int>(list)): ListCopy_5(...) == System.Collections.Generic.List`1[System.Int32] 10 iterations done in 480 ms. Average time: 48.00000 ms.

Recommend

  • Creating a service for user (S4U) token
  • Is this legal in Fortran: dot_product(x, x)?
  • ChangeDetectionStrategy.OnPush doesn't act how I expect it to
  • Compare two table and find matching columns
  • Symfony 2: Disable Doctrine event listener in ContainerAwareCommand
  • Find all classes in a Javascript application that extend a base class
  • Slf4j with Log4j does not print wrapped exception (caused by) when wrapper exception has a message
  • better understanding type promotion of variadic parameters in c
  • Redirect index.php to root (except query string)
  • Wordpress form with file upload submit with Ajax
  • Unable to access local Web API from Visual Studio 2015 WIndows 10 Phone Emulator
  • QR code webcam scanner c#
  • Matplotlib log-scale tick labels, minus sign too long in latex font
  • JSF Datatable link to another page
  • Image is rotated 90 degrees when using clipToMask
  • Docker image with python3, chromedriver, chrome & selenium
  • How should I emulate a mouseenter event using jquery's live functionality?
  • Dynamic parameters for attributes
  • Opencart get product downloads
  • Understanding HttpServletRequest and cookies in JSF
  • Display Windows Touch Keyboard
  • Apple Push Notifications - App store submission
  • Running Applescript from a Cocoa application
  • How to change WebBrowser fullscreen video mode?
  • Using one probability set to generate another [duplicate]
  • Using PHP & Tornado
  • Why clearfsimport command adds file to source control with a size zero?
  • Python ctypes: Prototype with LPCSTR [out] parameter
  • How to move to lines with the same indentation in Visual Studio Code
  • How do I set the logging properties in a spring java configuration?
  • Load php page results into div with ajax with link?
  • How does the dispatcher work when mixing sync/async with serial/concurrent queue?
  • Unable to run testNG tests from maven
  • How to display converted time zones in a 'generic week' (Sunday thru Saturday)?
  • How can i move Clearcase dyamic/snapshot views to another host (Linux)
  • Google Spreadsheet Script to Blink a range of Cells