2011-06-29 14 views
8

patrzę na niektóre kodu, które odbywają się IEnumerable<T> i konwertuje go na List<T> więc można go używać List<T>.Find(predicate):Odpowiednik LINQ listy <T> .Find()?

var myEnumerable = ...; 
var myList = new List<T>(myEnumerable); 
var match = myList.Find(value => value.Aaa == aaa && value.Bbb == bbb); 

Czy istnieje sposób, aby przepisać ten pomocą LINQ extension methods że ten sam efekt, ale bez budowanie dodatkowego List<T> jako etap pośredni?

FirstOrDefault(source, predicate) metodę rozszerzenia wygląda dobrym kandydatem, ale próbuje dowiedzieć się, czy jest to dokładnie równoważne Find robi moja głowa boli.

Odpowiedz

10

LINQ equivelent byłoby użyć FirstOrDefault:

var match = myEnumerable.FirstOrDefault(value => value.Aaa == aaa && value.Bbb == bbb); 
+0

Podejrzewam, że tak, ale dobrze jest usłyszeć potwierdzenie od kogoś, kto ma więcej przedstawicieli niż ja (uśmiech). Czy w ten sam sposób traktujesz wszystkie przypadki skrajne? (Pusty zbiór, nic co pasuje, inne wyjątkowe warunki) –

+0

@Joe: Tak. Daje ci te same wyniki - pierwszy mecz, lub 'default (T)' w przypadku braku pasujących elementów. Jest efektywnie identyczny, z tym wyjątkiem, że działa na dowolnym 'IEnumerable ' –

1

Albo można zrobić w następujący sposób:

var match = myEnumerable.Where(value => value.Aaa == aaa && value.Bbb == bbb) 
         .FirstOrDefault(); 
+0

To jest zapytanie dwa razy, co nie jest potrzebne, ponieważ można osiągnąć pożądany wynik tylko z FirstOrDefault –

+2

@danderson: Not true - LINQ używa odroczonego wykonywania, więc "zapytanie "przestanie wykonywać, gdy tylko pierwszy element zostanie znaleziony. To naprawdę nie jest dużo mniej wydajne niż użycie FirstOrDefault bezpośrednio [bardzo nieznacznie mniej wydajnie, ale tylko mikroskopowo więc]. Ciągle jest tylko co najwyżej jedna iteracja ... –

+0

Przeprowadziłem testy wydajności i zweryfikowałem to, ale czy znasz również artykuły, biuletyny lub łącza MSDN, które wyjaśniają, jak działa LINQ pod maską? Nie znalazłem jeszcze żadnego na MSDN –

13

Tylko dla odniesienia, tutaj jest tabela z jakimś starym stylu 2 .NET List<> Metody instancji i ich równoważne metody rozszerzeń w Linq:

METHOD IN List<>        METHOD IN Linq 
------------------------------------------------------------------------------------------ 

list.Contains(item)       query.Contains(item) 

list.Exists(x => x.IsInteresting())   query.Any(x => x.IsInteresting()) 
list.TrueForAll(x => x.IsInteresting())  query.All(x => x.IsInteresting()) 

list.Find(x => x.IsInteresting())    query.FirstOrDefault(x => x.IsInteresting()) 
list.FindLast(x => x.IsInteresting())   query.LastOrDefault(x => x.IsInteresting()) 

list.FindAll(x => x.IsInteresting())   query.Where(x => x.IsInteresting()) 

list.ConvertAll(x => x.ProjectToSomething()) query.Select(x => x.ProjectToSomething()) 

Oczywiście niektóre z nich nie są całkowicie równoważne. W szczególności Linq's Where i Select używają odroczonego wykonywania, natomiast FindAll i ConvertAll z List<> wykona natychmiast i zwróci referencję do nowej instancji List<>.

FindLast będzie często szybszy niż LastOrDefault, ponieważ FindLast faktycznie wyszukuje począwszy od końca. Z drugiej strony LastOrDefault(predicate) zawsze przechodzi przez całą sekwencję (począwszy od pierwszego elementu), a następnie zwraca najbardziej "ostatnie" dopasowanie.

+2

Świetna odpowiedź i ciekawy komentarz na temat FindLast w porównaniu do LastOrDefault. –