2009-03-23 14 views
27

Przeglądam ogólną listę, aby znaleźć elementy na podstawie określonego parametru.Ogólna lista FindAll() vs. foreach

Ogólnie, jaka byłaby najlepsza i najszybsza implementacja?
1. Przelotowe każdego elementu z listy i zapisać poszczególne dopasowanie do nowej listy i powrocie, że

foreach(string s in list) 
{ 
    if(s == "match") 
    { 
     newList.Add(s); 
    } 
} 

return newList; 

Albo
2. Stosując metodę FindAll i przekazując jej delegata.

newList = list.FindAll(delegate(string s){return s == "match";}); 

Czy obie nie działają w ~ O (N)? Jaka byłaby najlepsza praktyka?

Pozdrawiam, Jonathan

Odpowiedz

41

Powinieneś zdecydowanie użyć metody FindAll lub równoważnej metody LINQ. Rozważ także użycie bardziej zwartego lambda zamiast delegata, jeśli możesz (wymaga C# 3.0):

var list = new List<string>(); 
var newList = list.FindAll(s => s.Equals("match")); 
9

chciałbym użyć FindAll method w tym przypadku, ponieważ jest bardziej zwięzły i IMO, ma łatwiejszy czytelność.

Masz rację, że są one dość dużo zamiar wykonać zarówno w O (N) czasu, chociaż foreach statementpowinny być nieznacznie szybciej dana nie ma wykonać wywołanie delegata (delegatów ponieść niewielki narzut, w przeciwieństwie do metod bezpośredniego wywoływania).

muszę podkreślić, jak nieznaczna różnica ta, to więcej niż prawdopodobne, nigdy nie sprawi różnicy, chyba że robisz masywny liczbę operacji na masywnej listy.

Jak zawsze, sprawdź, gdzie występują wąskie gardła i postępuj właściwie.

4

List.FindAll to O (n) i przeszuka całą listę.

Jeśli chcesz uruchomić własny iterator z foreach, polecam użycie instrukcji yield i zwracanie IEnumerable, jeśli to możliwe. W ten sposób, jeśli będziesz potrzebować tylko jednego elementu swojej kolekcji, będzie to szybsze (ponieważ możesz zatrzymać rozmówcę bez wyczerpywania całej kolekcji).

W przeciwnym razie należy trzymać się interfejsu BCL.

3

Jakakolwiek różnica w wynikach będzie wyjątkowo niewielka. Sugerowałbym FindAll dla jasności lub, jeśli to możliwe, Enumerable.Where. Wolę używać metod Enumerable, ponieważ pozwala to na większą elastyczność w refaktoryzacji kodu (nie polegasz na List<T>).

5

Jonathan,

Dobrą odpowiedź można znaleźć na to w rozdziale 5 (względy wydajności) o Linq To Action.

Mierzą one dla każdego wyszukiwania, które wykonuje około 50 razy i że przychodzi z foreach = 68ms na cykl/List.FindAll = 62ms na cykl. Naprawdę, prawdopodobnie w twoim interesie jest stworzenie testu i przekonaj się sam.

2

Tak, obie implementacje to O (n). Muszą sprawdzić każdy element na liście, aby znaleźć wszystkie dopasowania. Pod względem czytelności wolałbym także FindAll. Aby zapoznać się z kwestiami dotyczącymi wydajności, należy zapoznać się z LINQ in Action (Ch 5.3). Jeśli używasz C# 3.0, możesz również zastosować wyrażenie lambda. Ale to tylko wisienka na torcie:

var newList = aList.FindAll(s => s == "match"); 
1

Im z lambdas

List<String> newList = list.FindAll(s => s.Equals("match")); 
0

Jeżeli zespół C# poprawiło wydajność LINQ i FindAll następujący artykuł zdaje się sugerować, że for i foreach przewyższyłby liczbę LINQ i FindAll dla wyliczenia obiektów: LINQ on Objects Performance.

Ten artykuł pochodzi z marca 2009 roku, tuż przed początkiem tego postu.