Общий список FindAll() против foreach
Я просматриваю общий список, чтобы найти элементы на основе определенного параметра.
В целом, какая была бы лучшая и быстрая реализация?
1. Прокручивание каждого элемента в списке и сохранение каждого совпадения в новом списке и возвращение этого
foreach(string s in list)
{
if(s == "match")
{
newList.Add(s);
}
}
return newList;
Или
2. Используя метод FindAll и передав ему делегат.
newList = list.FindAll(delegate(string s){return s == "match";});
Разве они оба не работают в ~ O (N)? Что было бы лучше всего здесь?
С уважением,
Джонатан
Ответы
Ответ 1
Вы должны определенно использовать метод FindAll
или эквивалентный метод LINQ. Кроме того, рассмотрите возможность использования более сжатой лямбды вместо вашего делегата, если вы можете (требуется С# 3.0):
var list = new List<string>();
var newList = list.FindAll(s => s.Equals("match"));
Ответ 2
В этом случае я бы использовал метод FindAll
, поскольку он более краток и IMO имеет более удобную читаемость.
Вы правы, что они в значительной степени будут выполнять в O (N) время, хотя foreach
statement должен быть немного быстрее, поскольку ему не нужно выполнять вызов делегата (делегаты несут небольшие накладные расходы, а не напрямую вызывающие методы).
Я должен подчеркнуть, насколько незначительна эта разница, она более чем вероятно никогда не изменит ситуацию, если вы не делаете огромное количество операций в массивном списке.
Как всегда, проверьте, где узкие места и действуют надлежащим образом.
Ответ 3
Джонатан
Хороший ответ вы можете найти в главе 5 (соображения производительности) Linq To Action.
Они измеряют a для каждого поиска, который выполняется около 50 раз, и который встречается с foreach = 68 мс за цикл /List.FindAll = 62ms за цикл. На самом деле, вероятно, вам будет интересно только создать тест и убедиться в этом.
Ответ 4
List.FindAll - это O (n) и будет искать весь список.
Если вы хотите запустить свой собственный итератор с foreach, я бы рекомендовал использовать оператор yield и, если возможно, возвратил IEnumerable. Таким образом, если вам в итоге понадобится только один элемент вашей коллекции, он будет быстрее (поскольку вы можете остановить своего абонента без исчерпания всей коллекции).
В противном случае, придерживайтесь интерфейса BCL.
Ответ 5
Любая перформанса будет крайне незначительной. Я бы предложил FindAll для ясности или, если возможно, перечислить. Где. Я предпочитаю использовать методы Enumerable, потому что он обеспечивает большую гибкость при рефакторинге кода (вы не принимаете зависимость от List<T>
).
Ответ 6
Да, обе реализации - O (n). Они должны посмотреть на каждый элемент в списке, чтобы найти все совпадения. С точки зрения удобочитаемости я также предпочел бы FindAll. Для соображений производительности смотрите LINQ в действии (Ch 5.3). Если вы используете С# 3.0, вы также можете применить выражение лямбда. Но это только глазурь на торте:
var newList = aList.FindAll(s => s == "match");
Ответ 7
Im с Lambdas
List<String> newList = list.FindAll(s => s.Equals("match"));
Ответ 8
Если команда С# не улучшила производительность для LINQ
и FindAll
, следующая статья, похоже, предполагает, что for
и foreach
будут превосходить LINQ
и FindAll
при перечислении объектов: LINQ для производительности объектов.
Этот артикул был датирован март 2009 года, как раз перед этим сообщением, которое первоначально было задано.