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.


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


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ę!



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.



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.


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> ]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.