Różnica między Select i ConvertAll w C #

117

Mam listę:

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

Chcę zastosować transformację do elementów mojej listy. Mogę to zrobić na dwa sposoby:

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

Jaka jest różnica między tymi dwoma sposobami?

AndreyAkinshin
źródło
16
Nie musisz .ToList () po ConvertAll ().
Gleno
nigdy nie słyszałem o ConvertAll, dowiedziałem się dziś czegoś nowego
Amit Bisht

Odpowiedzi:

117

Selectjest metodą rozszerzenia LINQ i działa na wszystkich IEnumerable<T>obiektach, podczas gdy ConvertAlljest implementowana tylko przez List<T>. ConvertAllMetoda istnieje od .NET 2.0, podczas gdy LINQ został wprowadzony z 3,5.

Należy sprzyjać Selectnad ConvertAlljak to działa na wszelkiego rodzaju listy, ale w zasadzie to samo.

Oliver Hanappi
źródło
7
A co z występami? Jeśli mam listę, czy bardziej wydajne jest użycie ConvertAll lub Select?
Nicolas,
@Nicolas: Całkowity czas wykonania jest mniej więcej taki sam, ale przetwarzają je inaczej, więc pasują do różnych lokalizacji. Dodałem trochę na ten temat w mojej odpowiedzi.
Guffa,
3
Nie możesz porównać Selecti ConvertAll. Pierwsza z nich wybiera każdy element w sekwencji i możesz z nim zrobić, co chcesz. Ten ostatni ma jasny zamiar: przekształcić ten element w coś innego.
Tim Schmelter,
1
Co ciekawe, Klasa List <T> zawiera kilka metod, które mają prawie dokładne dopasowania w LINQ. Exists -> Any, Find -> First, FindAll -> Where, FindLast -> Last, TrueForAll -> All
Mikal Schacht Jensen
Różnica między ConvertAll i Select polega na tym, że ConvertAll przydzieli rozmiar listy wcześniej. W przypadku dużej sekwencji będzie to miało wpływ na wydajność. Dlatego jeśli Twoim celem jest wydajność, użyj ConvertAll. Jeśli wydajność nie jest problemem, użyj Select, ponieważ jest bardziej idiomatyczny w języku i mówi przyszłym czytelnikom, że wydajność nie była problemem.
Durdsoft
82

ConvertAllnie jest rozszerzeniem, jest to metoda z klasy list. Nie musisz wywoływać ToListwyniku, ponieważ jest to już lista:

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

Różnica polega więc na tym, że ConvertAllmetoda może być używana tylko na liście i zwraca listę. SelectSposób można stosować w każdej kolekcji implementującej IEnumerable<T>interfejs i zwróciIEnumerable<T> .

Przetwarzają też inaczej, więc mają swoje mocne strony w różnych sytuacjach. Te ConvertAllmetoda przebiega przez liście i tworzy nową listę w jednym kroku, natomiast Selectmetoda wykorzystuje leniwe wykonanie i przetwarza tylko elementy, jak ich potrzebujesz. Jeśli nie potrzebujesz całego przedmiotu, Selectmetoda jest bardziej wydajna. Z drugiej strony, po ConvertAllzwróceniu listy, nie musisz zachowywać oryginalnej listy.

Guffa
źródło
Prawdopodobnie nigdy nie trzeba „zachowywać oryginalnej listy”: zostanie to zrobione w razie potrzeby przez GC.
user2864740
8
@ user2864740: Tak, to prawda, jeśli źródło jest ściśle listą w pamięci. Jeśli jest odczytywany na przykład z pliku, musisz pozostawić plik otwarty, dopóki nie przetworzysz wyniku z pliku Select.
Guffa
19

Pierwsza odpowiedź nie powinna być zaakceptowana. Jestem poprzednim MVP Microsoft C # 2007.

W przeciwieństwie do przyjętej odpowiedzi, ConvertAlljest dużo bardziej skuteczny niż połączenie SelectiToList() .

Po pierwsze, ConvertAll jest ściśle szybszy i wykorzystuje do tego minimalną ilość pamięci. To samo co Array.ConvertAll vs Select i ToArray. Byłoby to znacznie bardziej oczywiste w przypadku tablicy o większej długości lub wielu wywołań w pętli.

1) ConvertAllzna rozmiar ostatecznej listy i unika ponownego przydzielania tablicy podstawowej.ToList() będzie wielokrotnie zmieniać rozmiar tablicy.

2) ToListbędzie wolniej IEnumerable<>wywoływać interfejs , podczas gdyConvertAll przejdzie przez podstawową tablicę bez dodatkowych wywołań lub sprawdzania zakresu.

3) Wybierz utworzy dodatkowy IEnumerable<T>obiekt.

Wesner Moise
źródło
1

Wiem, że to trochę za późno, ale nadal dodałem, ponieważ może to być przydatne dla innych w przyszłości.

W przypadku używania go w wyrażeniu zapytania EntityFramework nie zaleca się używania ConvertAll (), ponieważ ocenia wyrażenie, zamiast pozostawiać je jako wyrażenie do wykorzystania w przyszłości. To poważnie obniża wydajność wykonywania zapytań do bazy danych, ponieważ musiałoby wykonać określoną liczbę wywołań przed oceną końcowego wyrażenia.

Navap
źródło
9
Nie do końca. Jak wskazuje Guffa w tej odpowiedzi , ConvertAll jest metoda naList<T> . Do czasu mieć listę, już oceniany swój wyraz. Ale masz rację - jeśli nie chcesz oceniać wszystkich, Selectlepiej.
Wai Ha Lee