Diferença entre Select e ConvertAll em C #

117

Eu tenho alguma lista:

List<int> list = new List<int> { 1, 2, 3, 4, 5 };

Quero aplicar alguma transformação aos elementos da minha lista. Posso fazer isso de duas maneiras:

List<int> list1 = list.Select(x => 2 * x).ToList();
List<int> list2 = list.ConvertAll(x => 2 * x).ToList();

Qual é a diferença entre essas duas formas?

AndreyAkinshin
fonte
16
Você não precisa .ToList () após ConvertAll ().
Gleno
nunca ouvi falar de ConvertAll, conheci algo novo hoje
Amit Bisht,

Respostas:

117

Selecté um método de extensão LINQ e funciona em todos os IEnumerable<T>objetos, embora ConvertAllseja implementado apenas por List<T>. O ConvertAllmétodo existe desde .NET 2.0, enquanto LINQ foi introduzido com 3.5.

Você deve favorecer Selectsobre ConvertAllcomo ele funciona para qualquer tipo de lista, mas eles fazem o mesmo, basicamente.

Oliver Hanappi
fonte
7
E as performances? Se eu tiver uma lista, é mais eficiente usar ConvertAll ou Select?
Nicolas
@Nicolas: O tempo total de execução é quase o mesmo, mas eles fazem o processamento de forma diferente para que se encaixem em diferentes situações. Eu adicionei algo sobre isso em minha resposta.
Guffa
3
Você não pode comparar Selecte ConvertAll. O primeiro seleciona cada item em uma sequência e você está livre para fazer o que quiser com ele. Este último tem uma intenção clara: converter este item em outra coisa.
Tim Schmelter
1
Curiosamente, a classe List <T> contém vários métodos que têm correspondências quase exatas no LINQ. Exists -> Any, Find -> First, FindAll -> Where, FindLast -> Last, TrueForAll -> All
Mikal Schacht Jensen
A diferença entre ConvertAll e Select é que ConvertAll alocará o tamanho da lista de antemão. Para uma sequência grande, isso fará uma diferença no desempenho. Portanto, se o seu objetivo é o desempenho, use ConvertAll. Se o desempenho não for uma preocupação, use Select, pois é mais idiomático no idioma e informa aos leitores futuros que o desempenho não é uma preocupação.
Durdsoft
82

ConvertAllnão é uma extensão, é um método na classe de lista. Você não precisa chamar ToListo resultado, pois já é uma lista:

List<int> list2 = list.ConvertAll(x => 2 * x);

Portanto, a diferença é que o ConvertAllmétodo só pode ser usado em uma lista e retorna uma lista. O Selectmétodo pode ser usado em qualquer coleção que implemente a IEnumerable<T>interface e retorna um IEnumerable<T>.

Além disso, eles fazem o processamento de forma diferente, portanto, eles têm seus pontos fortes em diferentes situações. O ConvertAllmétodo percorre a lista e cria uma nova lista de uma vez, enquanto o Selectmétodo usa a execução lenta e processa os itens apenas quando você precisa deles. Se você não precisa de todos os itens, o Selectmétodo é mais eficiente. Por outro lado, depois de ConvertAlldevolver a lista, não é necessário guardar a lista original.

Guffa
fonte
Indiscutivelmente, nunca é necessário "manter a lista original": isso será feito conforme a necessidade do CG.
user2864740
8
@ user2864740: Sim, isso é verdade se a fonte for estritamente uma lista na memória. Se for lido, por exemplo, de um arquivo, você precisará mantê-lo aberto até que tenha processado o resultado do Select.
Guffa
19

A primeira resposta não deve ser a aceita. Eu sou um ex-2007 C # Microsoft MVP.

Em contraste com a resposta aceita, ConvertAllé muito mais eficiente do que a combinação de Selecte ToList().

Em primeiro lugar, ConvertAllé estritamente mais rápido e usa o mínimo de memória para isso. O mesmo que Array.ConvertAll vs Select e ToArray. Isso seria muito mais evidente com uma matriz de comprimento maior ou muitas chamadas em um loop.

1) ConvertAllconhece o tamanho da lista final e evita realocar o array base. ToList() continuará a redimensionar o array várias vezes.

2) ToListfará IEnumerable<>chamadas de interface mais lentas , enquanto ConvertAllfará um loop pela matriz subjacente sem chamadas extras ou verificações de intervalo.

3) Selecionar criará um IEnumerable<T>objeto extra .

Wesner Moise
fonte
1

Eu sei que é um pouco tarde, mas ainda assim adicionei porque isso poderia ser de alguma utilidade para outros no futuro.

Ao usá-lo na expressão de consulta EntityFramework, não é recomendado usar ConvertAll (), pois ele avalia a expressão em vez de deixá-la como expressão para uso futuro. Isso degrada seriamente o desempenho da execução da consulta ao banco de dados, pois seria necessário fazer várias chamadas antes de avaliar a expressão final.

Navap
fonte
9
Não exatamente. Como Guffa aponta nesta resposta , ConvertAll é um métodoList<T> . Quando você tem a lista, já avaliou sua expressão. Mas você está certo - se você não quiser avaliar tudo, Selecté preferível.
Wai Ha Lee