27

What is the fastest way of taking a list of primitives and converting it to a nullable list of primitives? For example: List<int> to List<int?>.

The easy solution, creating a new list and adding every item with a foreach loop, takes too much time.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
user1039544
  • 321
  • 1
  • 3
  • 6
  • what's your definition of too much time? The only way is to loop (either with `foreach` or `LINQ`) – psubsee2003 Mar 03 '13 at 10:12
  • 2
    not to be smart, but aren't you able to refactor you code slightly so that you don't have to convert? – bas Mar 03 '13 at 11:13
  • Possible duplicate of [Implicit convert List to List](http://stackoverflow.com/questions/14394016/implicit-convert-listint-to-listint) – Wesam Oct 31 '16 at 08:52

4 Answers4

60

There is no way faster than creating a new list:

var newList = list.Select( i => (int?)i ).ToList();

However using LINQ is slower than using a bare loop.

The fastest way is to use a List<int?> with pre-allocated capacity:

List<int?> newList = new List<int?>(list.Count); // Allocate enough memory for all items
foreach (var i in list)
    newList.Add(i);

If you are seeking for in-place type change of list items, it's not possible.

Mohammad Dehghan
  • 17,853
  • 3
  • 55
  • 72
  • 1
    Well it would be faster not using LINQ. – Jeff Mercado Mar 03 '13 at 10:18
  • @JeffMercado Actually, I agree :-) I've not measured the performance difference, but I guess it is negligible. – Mohammad Dehghan Mar 03 '13 at 10:21
  • 3
    @Fuex Interesting. My test also shows that a bare loop is 30%-40% faster than LINQ (with 1,000,000) items. – Mohammad Dehghan Mar 03 '13 at 12:07
  • Really how did you know iterating over items will outperform somethings like `Cast` method?! :)) I bet you didn't measured before! – Arman Ebrahimpour May 25 '20 at 21:54
  • 1
    @ArmanEbrahimpour I measured This answer is for 7 years ago. I knew LINQ operators add some overhead, but I thought it is negligible. Now I have knowledge of all the overhead and also the compiler and runtime optimizations that may remove the overhead! Remember, you should **always** measure before optimizing! – Mohammad Dehghan May 26 '20 at 06:21
16

Instead of Select you can stick to the Cast LINQ-operator:

List<int> first = new List<int>() {1, 2, 3};
List<int?> second = first.Cast<int?>().ToList();
Matten
  • 17,365
  • 2
  • 42
  • 64
8

If you want to know what's the faster solution, you should do a little benchmark by using the three different ways:

List<int> list = Enumerable.Range( 0, 10000 ).ToList( );
Stopwatch sw = Stopwatch.StartNew( );

for ( int i = 0; i < 100000; i++ ) {
   List<int?> newList = new List<int?>( );
   foreach( int integer in list )
      newList.Add( ( int? ) integer );
}

sw.Stop( );
TimeSpan timespan = sw.Elapsed;
Console.WriteLine( String.Format( "Foreach: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );
sw.Restart( );

for ( int i = 0; i < 100000; i++ ){
   List<int?> newList = list.Select( x => ( int? ) x ).ToList( );
}

sw.Stop( );
timespan = sw.Elapsed;
Console.WriteLine( String.Format( "LINQ-Select: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );
sw.Restart( );

for ( int i = 0; i < 100000; i++ ){
   List<int?> newList = list.Cast<int?>( ).ToList( );
}

sw.Stop();
timespan = sw.Elapsed;
Console.WriteLine( String.Format( "LINQ-Cast: {0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10 ) );

Results:

Benchmark

As we could expect the best way is the first solution (foreach) which means loop through the elements, cast and add them to a new list.

Omar
  • 16,329
  • 10
  • 48
  • 66
  • 1
    Have you tried it without foreach and using a simple "for(i = 0; i < list.Count();i++")? as in http://stackoverflow.com/questions/365615/in-net-which-loop-runs-faster-for-or-foreach – EGOrecords Mar 03 '13 at 11:48
  • Interesting fact, so the SO-Answer I provided is a little bit out of date ;) – EGOrecords Mar 03 '13 at 12:01
  • 1
    Don't forget to set the Capacity of the list in the foreach case to make it faster and leaner. – Hans Passant Mar 03 '13 at 13:04
0

It's not a new question, but I use this code currently; I share it with the hope that it could help others with the same question: List with pre-allocated + Linq:

var branchIds = new List<int?>(branches.Count);
branchIds.AddRange(branches.Select(int.Parse).Select(brId => (int?)brId));
Elnaz
  • 2,854
  • 3
  • 29
  • 41
  • You don't show what `branches` is, but since you're converting it with `int.Parse` it must be some `string` collection, whereas the question is how to create a `List` from a `List`. – Lance U. Matthews Apr 24 '21 at 06:00