Difference between Select and ConvertAll in C#
Select
is a LINQ extension method and works on all IEnumerable<T>
objects whereas ConvertAll
is implemented only by List<T>
. The ConvertAll
method exists since .NET 2.0 whereas LINQ was introduced with 3.5.
You should favor Select
over ConvertAll
as it works for any kind of list, but they do the same basically.
C# List .ConvertAll Efficiency and overhead
No better way to find out than to go directly to the source, literally :)
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs#dbcc8a668882c0db
As you can see, there's no special magic going on. It just iterates over the list and creates a new item by the converter function that you specify.
To be honest, I was not aware of this method. The more idiomatic .NET way to do this kind of projection is through the use of the Select
extension method on IEnumerable<T>
like so: source.Select(input => new Something(input.Name))
. The advantage of this is threefold:
- It's more idomatic as I said, the
ConvertAll
is likely a remnant of the pre-C#3.0 days. It's not a very arcane method by any means andConvertAll
is a pretty clear description, but it might still be better to stick to what other people know, which isSelect
. - It's available on all
IEnumerable<T>
, whileConvertAll
only works on instances ofList<T>
. It doesn't matter if it's an array, a list or a dictionary,Select
works with all of them. Select
is lazy. It doesn't do anything until you iterate over it. This means that it returns anIEnumerable<TOutput>
which you can then convert to a list by callingToList()
or not if you don't actually need a list. Or if you just want to convert and retrieve the first two items out of a list of a million items, you can simply dosource.Select(input => new Something(input.Name)).Take(2)
.
But if your question is purely about the performance of converting a whole list to another list, then ConvertAll
is likely to be somewhat faster as it's less generic than a Select
followed by a ToList
(it knows that a list has a size and can directly access elements by index from the underlying array for instance).
How to choose between Convert and Select with LINQ to objects?
ConvertAll
has been around since .Net 2.0, whereas LINQ is newer. Select
appears to be more general, and to make ConvertAll
redundant.
I can't think of any situation where you would need to use ConvertAll
in new code. Select
is better-known, more general, and works with the other features of LINQ (such as direct translation to SQL queries in LINQ to SQL).
linq .Cast or cast inside ConvertAll for a list
TL;DR: ConvertAll
makes 1 memory allocation, but .Cast.ToList
more than one in most cases.
Most LINQ extensions (like .Cast<T>()
) result in a deferred execution IEnumerable<T>
that can't be cast to ICollection<T>
(can't get the .Count
of the result).
When the result can be cast to ICollection<T>
, .ToList
and .ToArray
can make just one memory allocation to copy the elements, but when it can't:
- initially 4 element buffer array is allocated for non-empty source
- when space is needed for more elements, new array is allocated with double the size of the previous one
- elements are copied from the old array to the new one, and the old array is later deallocated by the garbage collector.
Update
Surprisingly, the difference doesn't seem nowhere near as significant as I expected:
method elapsed ratio count
Cast.ToList 00:00:14.4487329 1.3719890831991 123456789
ConvertAll 00:00:10.5312302 0.728868773261865
Cast.ToList 00:00:01.4959734 1.50233158227713 12345678
ConvertAll 00:00:00.9957678 0.665632016125407
Cast.ToList 00:00:00.1252968 2.45948743599897 1234567
ConvertAll 00:00:00.0509442 0.40658878161491
Cast.ToList 00:00:00.0082611 3.99145006839945 123456
ConvertAll 00:00:00.0020697 0.250535515380002
Cast.ToList 00:00:00.0008097 0.620558719826417 12345
ConvertAll 00:00:00.0013049 1.61145104895105
Cast.ToList 00:00:00.0001812 0.193207547169811 1234
ConvertAll 00:00:00.0009378 5.17578125
Cast.ToList 00:00:00.0001433 0.149501661129568 123
ConvertAll 00:00:00.0009587 6.68888888888889
So, race your horses!
int c = 123; var L = Enumerable.Range(0, c).ToList();
GC.Collect(); var sw1 = Stopwatch.StartNew(); L.Cast<object>().ToList(); sw1.Stop();
GC.Collect(); var sw2 = Stopwatch.StartNew(); L.ConvertAll(i => (object)i); sw2.Stop();
MessageBox.Show($"Cast.ToList\t{sw1.Elapsed}\t{(double)sw1.ElapsedTicks / sw2.ElapsedTicks}\n" +
$"ConvertAll \t{sw2.Elapsed}\t{(double)sw2.ElapsedTicks / sw1.ElapsedTicks}");
Array.ConvertAll() and ToArray() method, which is better?
Firstly these aren't equivalent, in one version you are using int.Parse(x)
in another Convert.ToInt32(sTemp)
That aside, you have found a perfect example of how to do something more than one way... In programming you will find this a lot.
ConvertAll()
Converts an array of one type to an array of another type.
Select()
Projects each element of a sequence into a new form.
ToArray()
Creates an array from a IEnumerable.
Technically, in combination they produce the same thing, yet got about it in slightly different ways due to the fact they are part of slightly different areas of the BCL that have concerns in slightly different domains.
Personally i don't see ConvertAll
used all that much these days as people are very familiar with LINQ and like to chain methods.
As to which is better for performance, we would have to write a lot of tests to figure this out, and it would come down to allocations verse speed per array size per platform. However, i feel the difference would be relatively indistinguishable in day to day, and my guess is you would be struggling to find very much performance difference at all at any significant sigma categorically.
In short, use what You like
Converter And ConvertAll alternative for UWP C#
As you said, in UWP there is no System.Converter and Array.ConvertAll. You can however use the LINQ method Select to do the same work.
Trying to define method similar to ListT.ConvertAll(TOutput)
What you're attempting is called a projection
.
An extension method is already included in the .NET Framework to achieve this. IEnumerable.Select
, and you can use it in the fashion below.
void Main()
{
List<Foo> foos = new List<Foo>
{
new Foo { Name = "Fu" },
new Foo { Name = "Foe" },
new Foo { Name = "Thumb" }
};
IEnumerable<Bar> bars = foos.Select(foo => new Bar
{
BarId = foo.Id,
Name = foo.Name
});
}
public class Foo
{
public Foo() { Id = Guid.NewGuid().ToString(); }
public string Id { get; set; }
public string Name { get; set; }
}
public class Bar
{
public Bar()
{
this.BarId = Guid.NewGuid().ToString();
this.TimeCreated = DateTime.UtcNow;
}
public string BarId { get; set; }
public string Name { get; set; }
public DateTime TimeCreated { get; set; }
}
How it's implemented....
If you wanted to implement a custom solution yourself for the sake of learning, this is how you would go about doing it:
public static class Extensions
{
public static IEnumerable<TDestination> ConvertTo<TFrom, TDestination>(this IEnumerable<TFrom> fromCollection, Func<TFrom, TDestination> expression)
{
List<TDestination> destinationList = new List<TDestination>();
foreach (var element in fromCollection)
{
destinationList.Add(expression.Invoke(element));
}
return destinationList;
}
}
void Main()
{
List<Foo> foos = new List<Foo>
{
new Foo { Name = "Fu" },
new Foo { Name = "Foe" },
new Foo { Name = "Thumb" }
};
IEnumerable<Bar> customBars = foos.ConvertTo(foo => new Bar
{
BarId = foo.Id,
Name = foo.Name
});
}
Why does IList have fewer features than List?
Note that List<>
is an implementation of IList<>
with actual storage, i.e. it holds an array in the background. In general, an IList<>
can be a proxy to something else. In db4o and linq to sql, your IList<>
could 'point to a query', i.e. accessing the list will trigger a database operation.
This way, you can perform myList.Skip(600).Take(20);
to perform pagination and only in this step will the actual query be executed. A List<>
containing a million entries will be huge, while there may be IList<>
s that have a huge Count
, but don't eat a significant amount of memory - as long as you don't access the elements.
ConvertAll
will require each and every object be instantiated so it is a costly operation. Thus, it is better to make the operation explicit and force you to retrieve a specific implementation of the interface. Obviously, conversion requires all objects to be instantiated anyway, so there's no benefit in doing it lazily.
why does C# convertall require 2 parameters
You're using ConvertAll on an Array of cars (Car[]) instead of a List of cars (List) which does indeed require two type parameters1. If cars is a list your code will work.
Related Topics
How to Count the Number of Elements That Match a Condition with Linq
Referenced Project Gets "Lost" at Compile Time
How to Write a Unit Test to Determine Whether an Object Can Be Garbage Collected
Multiple Where Clauses with Linq Extension Methods
Why Does System.Threading.Timer Stop on Its Own
When Not to Use Yield (Return)
Get All Properties Which Marked Certain Attribute
Using C# to Search a CSV File and Pull the Value in the Column Next to It
Filter a List by Another List C#
Change Custom Attribute's Parameter at Runtime
View Nuget Package Dependency Hierarchy
Using C# to Authenticate User Against Ldap
String Interpolation VS String.Format
How to Merge Two Lists Using Linq
How to Know What Image Format I Get from a Stream
How to Click a Button in a Webbrowser Control
In C# What Category Does the Colon ":" Fall Into, and What Does It Really Mean