Linq: Jaka jest różnica między Select i Where

123

SelectI Wheremetody są dostępne w Linq. Co każdy programista powinien wiedzieć o tych dwóch metodach? Na przykład: kiedy używać jednego nad drugim, jakie są zalety używania jednego nad drugim itp.

SBurris
źródło
7
Myślę, że to pytanie nie powinno być oznaczone jako CW, prawdopodobnie mogłoby mieć ostateczną odpowiedź.
Brandon,
1
@Brandon nie ma nic złego w oznaczaniu czegoś CW, jeśli jest to obiektywne.
Rex M
@Rex, zgadzam się. Samo stwierdzenie, że różnica między Select i Where ma ostateczną odpowiedź, a druga część pytania byłaby prawdopodobnie oparta na powszechnie przyjętych praktykach. Wskazałem to tylko na wypadek, gdyby OP nie był pewien co do oznaczania rzeczy jako CW. Jeśli zamierzał, aby było CW, to jest w porządku.
Brandon
6
Jest w tym wiele nie tak. CW jest bezużyteczne, a staje się coraz większe, gdy ludzie zaznaczają pytania całkowicie losowo jako CW
jalf

Odpowiedzi:

127

Gdzie

znajduje pasujące elementy i zwraca tylko te, które pasują ( filtrowanie ).

-> IEnumerable<A>na IEnumerable<A>zewnątrz

Wybierz

zwraca coś dla wszystkich elementów w źródle ( projekcja / transformacja ). Tym czymś mogą być same przedmioty, ale zazwyczaj są to jakieś projekcje.

-> IEnumerable<A>na IEnumerable<B>zewnątrz

Drew Noakes
źródło
16
Selectzawsze zwróci tę samą liczbę elementów na liście (niezależnie od warunku filtru, który możesz mieć). Wheremoże zwrócić mniej elementów w zależności od stanu filtra.
goku_da_master
A oto przykład MSDN selecti tutaj jest jeden dlawhere
yazanpro
Przynajmniej dla mnie, mając pewne doświadczenie z innymi językami, pomaga to pomyśleć Where == filteriSelect == map
bgusach
52

Select i Where to dwa zupełnie różne operatory działające na IEnumerable s.

Pierwszy to tak zwany operator projekcji , a ostatni to operator ograniczeń .

Ciekawym sposobem uzyskania wglądu w zachowanie takich operatorów jest przyjrzenie się ich „typowi funkcjonalnemu”.

  • Wybierz: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; przyjmuje jako dane wejściowe zarówno IEnumerable zawierające elementy typu T1, jak i funkcję przekształcającą elementy typu T1 na elementy typu T2. Dane wyjściowe to IEnumerable zawierające elementy typu T2.

    Na tej podstawie można łatwo zgadnąć, że ten operator wygeneruje dane wyjściowe, stosując funkcję wejściową do każdego elementu wejściowego IEnumerable i zawijając wyniki do nowego IEnumerable.

    Za pomocą matematycznej jak notacji trwa na wejściu (a, b, c, ...) IEnumerable <T1> i f T1 → T2 i wytwarza (F (a), F (b), f (c) , ...): IEnumerable <T2>

  • Gdzie: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; ten pobiera element IEnumerable zawierający elementy typu T1 i predykat na T1 (to znaczy funkcję, która generuje wynik boolowski dla danych wejściowych typu T1). Widzisz, że dane wyjściowe są również IEnumerable zawierające elementy typu T1.

    Tym razem można by się domyślić, że element wejściowy IEnumerable będzie obecny na wyjściu IEnumerable w zależności od wyniku zastosowania predykatu do elementu. Dodając do tego semantykę nazwy operatora, możesz być pewien, że wygeneruje on wynik IEnumerable, pobierając z danych wejściowych tylko te elementy, które są szacowane na true w zastosowaniu predykatu.

Ludzie z doświadczeniem w programowaniu funkcjonalnym zwykle myślą w ten sposób. Pozwala wywnioskować (lub przynajmniej zgadywać ...), co robi operator, tylko patrząc na jego typ!

W ramach ćwiczenia spróbuj spojrzeć na inne operatory wprowadzone przez LINQ na IEnumerables i wydedukować ich zachowanie, zanim przejrzysz dokumentację!

Bruno Reis
źródło
48

Są różne:

Selectchodzi o transformację .

Wherechodzi o filtrowanie .

bruno conde
źródło
18

Select mapuje wyliczalną do nowej struktury. Jeśli dokonasz wyboru na IEnumerable, otrzymasz tablicę z taką samą liczbą elementów, ale innym typem w zależności od określonego mapowania. Where filtruje IEnumerable, aby uzyskać podzbiór oryginalnego IEnumerable.

Steve
źródło
16

Where ~ = Filtruj

Select ~ = Mapa

Obie wraca IEnumerable<T>

Downhillski
źródło
Po to tu przyjechałem! Dziękuję Ci!
Ben Sandeen
7

Jeśli wiesz, jak zaimplementowali Gdzie i wybierz metody rozszerzeń, możesz przewidzieć, co robi ... Próbowałem zaimplementować gdzie i wybrać metody rozszerzeń ... Możesz na to spojrzeć ...

Gdzie Wdrożenie ::

public static IEnumerable<Tsource> Where<Tsource> ( this IEnumerable<Tsource> a , Func<Tsource , bool> Method )
{

    foreach ( var data in a )
    {
        //If the lambda Expression(delegate) returns "true" Then return the Data. (use 'yield' for deferred return)
        if ( Method.Invoke ( data ) )
        {
            yield return data;
        }
    }
}

Wybierz realizację:

public static IEnumerable<TResult> Select<TSource , TResult> ( this IEnumerable<TSource> a , Func<TSource , TResult> Method )
{
    foreach ( var item in a )
    {
        //Each iteration call the delegate and return the Data back.(use 'yield' for deferred return)
        yield return Method.Invoke ( item );
    }
}

Moja implementacja działa dobrze dla każdej kolekcji ... Ale różni się od metod rozszerzeń zaimplementowanych przez Microsoft, ponieważ używają drzew wyrażeń do implementacji tego samego.

Sanu Uthaiah Bollera
źródło
1

W przypadku Select it możesz zmapować do IEnumerable nowej struktury.

  A.Select(x=>new X{UID=x.uid, UNAME=x.uname}) 
  //input as [IEnumerable<A>] -------->  return output as [IEnumerable<X> ]

Where () działa jako filtr IEnumerable, zwróci wynik na podstawie klauzuli where.

A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] -------->  return output as [IEnumerable<A> ]
Supriya Bhattacherjee
źródło