Вопрос

Я работаю с базой кода, где в списках необходимо часто искать один элемент.

Быстрее ли использовать предикат и Find(), чем вручную выполнять перечисление в списке?

например:

string needle = "example";
FooObj result = _list.Find(delegate(FooObj foo) {
    return foo.Name == needle;
});

против.

string needle = "example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)
        return foo;
}

Хотя они эквивалентны по функциональности, эквивалентны ли они и по производительности?

Это было полезно?

Решение

Они не эквивалентны по производительности.Метод Find() требует вызова метода (в данном случае делегата) для каждого элемента в списке.Вызов метода не является бесплатным и относительно дорого по сравнению со встроенным сравнением.Версия foreach не требует дополнительного вызова метода для каждого объекта.

Тем не менее, я бы не стал выбирать тот или иной вариант, основываясь на производительности, пока я на самом деле не профилировал свой код и не обнаружил, что это проблема.Я еще не обнаружил, что накладные расходы этого сценария могут быть проблемой "горячего пути" для кода, который я написал, и я часто использую этот шаблон с Find и другими подобными методами.

Другие советы

Если поиск по вашему списку сам по себе слишком медленный, вы, вероятно, можете сделать это лучше, чем линейный поиск.Если вы можете сохранить список отсортированным, вы можете использовать двоичный поиск, чтобы найти элемент за O (lg n) раз.

Если вы ищете весь лот, подумайте о замене этого списка словарем для индексации ваших объектов по имени.

Технически производительность во время выполнения версии делегата будет немного хуже, чем у другой версии, но в большинстве случаев вам будет трудно заметить какую-либо разницу.

Более важным (IHMO) является время выполнения кода, позволяющее написать то, что вы хотите, а не так, как вы этого хотите.Это существенно повышает ремонтопригодность.

Этот оригинальный код:

string needle = "example";
foreach (FooObj foo in _list)
{
    if (foo.Name == needle)        
        return foo;
}

требуется, чтобы любой сопровождающий прочитал код и понял, что вы ищете определенный элемент.

Этот код

string needle = "example";
return _list.Find(
    delegate(FooObj foo) 
    {
        return foo.Name == needle;
    });

дает понять, что вы ищете определенный товар - быстрее для понимания.

Наконец, этот код, использующий функции из C # 3.0:

string needle = "example";
return _list.Find( foo => foo.Name == needle);

делает точно то же самое, но в одной строке, которую еще быстрее прочитать и понять (ну, как только вы поймете лямбда - выражения, во всяком случае).

Таким образом, учитывая, что производительность альтернатив почти одинакова, выберите ту, которая облегчает чтение и обслуживание кода.

"Я работаю с базой кода, где Списки нужно быть часто просматриваемый для одного элемента"

Для повышения производительности лучше изменить структуру данных на Dictionary, а не List

Аналогичный вопрос был задан для List.ForEach противforeach-итерация (foreach против someList.Foreach(){}).

В этом случае List.ForEach был немного быстрее.

Как отметил Джаред, есть различия.

Но, как всегда, не волнуйтесь, если только вы не знаете, что это узкое место.И если это узкое место, это, вероятно, потому, что списки большие, и в этом случае вам следует рассмотреть возможность использования более быстрого поиска - хэш-таблицы или двоичного дерева, или даже просто сортировки списка и выполнения двоичного поиска, что даст вам производительность log (n), которая окажет гораздо большее влияние, чем настройка вашего линейного случая.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top