Разница между Select и ConvertAll в C #


117

У меня есть список:

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

Я хочу применить некоторую трансформацию к элементам моего списка. Я могу сделать это двумя способами:

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

В чем разница между этими двумя способами?


16
Вам не нужно .ToList () после ConvertAll ().
Gleno 02

никогда не слышал о ConvertAll, узнал что-то новое сегодня
Амит Бишт

Ответы:


117

Selectявляется методом расширения LINQ и работает со всеми IEnumerable<T>объектами, тогда ConvertAllкак реализуется только с помощью List<T>. Этот ConvertAllметод существует с .NET 2.0, тогда как LINQ был представлен в версии 3.5.

Вы должны способствовать Selectболее , ConvertAllкак это работает для любого вида списка, но они делают то же самое в принципе.


7
А что насчет спектаклей? Если у меня есть список, что более эффективно - использовать ConvertAll или Select?
Николас

@Nicolas: Общее время выполнения примерно одинаковое, но обработка выполняется по-разному, поэтому они подходят для разных ситуаций. Я добавил кое-что об этом в своем ответе.
Guffa

3
Нельзя сравнивать Selectи ConvertAll. Первый выбирает каждый элемент в последовательности, и вы можете делать с ним все, что хотите. У последнего есть четкое намерение: преобразовать этот предмет во что-нибудь другое.
Тим Шмелтер

1
Интересно, что класс List <T> содержит несколько методов, которые имеют почти точное соответствие в LINQ. Exists -> Any, Find -> First, FindAll -> Where, FindLast -> Last, TrueForAll -> All
Mikal Schacht Jensen

Разница между ConvertAll и Select в том, что ConvertAll заранее выделит размер списка. Для большой последовательности это повлияет на производительность. Таким образом, если ваша цель - производительность, используйте ConvertAll. Если производительность не вызывает беспокойства, используйте Select, поскольку он более идиоматичен в языке и сообщает будущим читателям, что производительность не вызывала беспокойства.
Durdsoft,

82

ConvertAllне является расширением, это метод класса списка. Вам не нужно вызывать ToListрезультат, так как это уже список:

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

Итак, разница в том, что ConvertAllметод можно использовать только в списке, и он возвращает список. SelectМетод может быть использован в любой коллекции , которая реализует IEnumerable<T>интерфейс, и он возвращает IEnumerable<T>.

Кроме того, они по-разному выполняют обработку, поэтому в разных ситуациях у них есть свои сильные стороны. В ConvertAllметоде проходит через список и создает новый список за один раз, в то время как Selectметод использует ленивое выполнение и обрабатывает только те элементы , как вам необходимо. Если вам не нужен весь элемент, Selectметод более эффективен. С другой стороны, после ConvertAllвозврата списка нет необходимости сохранять исходный список.


Возможно, никогда не нужно «сохранять исходный список»: это будет делать сборщик мусора по мере необходимости.
user2864740 01

8
@ user2864740: Да, это правда, если источник строго является списком в памяти. Если он читается, например, из файла, вам нужно держать файл открытым до тех пор, пока вы не обработаете результат из файла Select.
Guffa

19

Первый ответ не должен быть принятым. Я бывший MVP Microsoft по C # 2007 года.

В отличие от принятого ответа, ConvertAllнамного эффективнее, чем комбинация Selectи ToList().

Прежде всего, он ConvertAllработает строго быстрее и использует для этого минимальный объем памяти. То же, что и Array.ConvertAll vs Select и ToArray. Это было бы гораздо более очевидным с массивом большей длины или большим количеством вызовов внутри цикла.

1) ConvertAllзнает размер окончательного списка и избегает перераспределения базового массива. ToList() будет изменять размер массива несколько раз.

2) ToListбудет выполнять более медленные IEnumerable<>вызовы интерфейса , в то время как ConvertAllбудет проходить через базовый массив без дополнительных вызовов или проверок диапазона.

3) Select создаст дополнительный IEnumerable<T>объект.


1

Я знаю, что это немного поздно, но я все же добавил, потому что это может быть полезно для других в будущем.

При использовании его в выражении запроса EntityFramework не рекомендуется использовать ConvertAll (), поскольку он оценивает выражение, а не оставляет его как выражение для использования в будущем. Это серьезно ухудшает производительность выполнения запросов к базе данных, так как перед вычислением окончательного выражения потребуется выполнить несколько вызовов.


9
Не совсем. Как указывает Гуффа в этом ответе , ConvertAll это методList<T> . К тому времени, когда у вас есть список, вы уже оценили свое выражение. Но вы правы - если не хотите все оценивать, Selectлучше.
Вай Ха Ли
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.