user1039544
user1039544

Reputation: 321

Fastest way to convert List<int> to List<int?>

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.

Upvotes: 27

Views: 25255

Answers (4)

Moha Dehghan
Moha Dehghan

Reputation: 18472

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.

Upvotes: 60

Elnaz
Elnaz

Reputation: 2900

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));

Upvotes: 0

Omar
Omar

Reputation: 16623

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.

Upvotes: 8

Matten
Matten

Reputation: 17603

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();

Upvotes: 16

Related Questions