I metodi Select
e Where
sono disponibili in Linq. Cosa dovrebbe sapere ogni sviluppatore di questi due metodi? Ad esempio: quando usarli uno sull'altro, eventuali vantaggi nell'usare uno sull'altro, ecc.
I metodi Select
e Where
sono disponibili in Linq. Cosa dovrebbe sapere ogni sviluppatore di questi due metodi? Ad esempio: quando usarli uno sull'altro, eventuali vantaggi nell'usare uno sull'altro, ecc.
Risposte:
Dove
trova gli elementi che corrispondono e restituisce solo quelli che lo fanno ( filtraggio ).
-> IEnumerable<A>
dentro, IEnumerable<A>
fuori
Selezionare
restituisce qualcosa per tutti gli elementi nell'origine ( proiezione / trasformazione ). Quel qualcosa potrebbe essere gli oggetti stessi, ma più di solito sono una proiezione di qualche tipo.
-> IEnumerable<A>
dentro, IEnumerable<B>
fuori
Select
restituirà sempre lo stesso numero di elementi nell'elenco (indipendentemente dalla condizione di filtro che potresti avere). Where
può restituire meno elementi a seconda della condizione del filtro.
Where == filter
eSelect == map
Select e Where sono due operatori completamente diversi che agiscono su IEnumerable s.
Il primo è quello che chiamiamo un operatore di proiezione , mentre l'ultimo è un operatore di restrizione .
Un modo interessante per avere un'idea del comportamento di tali operatori è dare uno sguardo al loro "tipo funzionale".
Selezionare: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; prende come input sia un IEnumerable contenente elementi di tipo T1 sia una funzione che trasforma elementi di tipo T1 in elementi di tipo T2. L'output è un IEnumerable contenente elementi di tipo T2.
Da ciò, si può facilmente intuire che questo operatore produrrà il suo output applicando la funzione di input su ogni elemento dell'input IEnumerable e avvolgendo i risultati in un nuovo IEnumerable.
Utilizzando alcuni matematica simile notazione, prende come input (a, b, c, ...): IEnumerable <T1> e f: T1 → T2 e produce (f (a), f (b), f (c) , ...): IEnumerable <T2>
Dove: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; questo accetta un IEnumerable contenente elementi di tipo T1 e un predicato su T1 (cioè una funzione che produce un risultato booleano per un input di tipo T1). Si vede che l'output è anche un IEnumerable contenente elementi di tipo T1.
Questa volta si potrebbe ipotizzare che un elemento dell'input IEnumerable sarà presente sull'output IEnumerable a seconda del risultato dell'applicazione del predicato all'elemento. Aggiungendo a ciò la semantica del nome dell'operatore, si può essere certi che produrrà l'output IEnumerable prendendo dall'input solo quegli elementi che valgono true sull'applicazione del predicato.
Le persone con un background di programmazione funzionale di solito la pensano così. Ti permette di dedurre (o almeno indovinare ...) cosa fa un operatore solo guardando il suo tipo!
Come esercizio, prova a guardare altri operatori introdotti da LINQ su IEnumerables e deduci il loro comportamento, prima di guardare la documentazione!
Sono distinti:
Select
è tutta una questione di trasformazione .
Where
riguarda il filtraggio .
Seleziona mappa un enumerabile su una nuova struttura. Se esegui una selezione su un oggetto IEnumerable, otterrai un array con lo stesso numero di elementi, ma un tipo diverso a seconda della mappatura specificata. Where filtra l'IEnumerable in modo da fornire un sottoinsieme dell'originale IEnumerable.
Where
~ = Filtro
Select
~ = Mappa
Entrambi ritorna IEnumerable<T>
Se sai come hanno implementato Dove e seleziona i metodi di estensione puoi prevedere cosa sta facendo ... Ho provato a implementare dove e selezionare i metodi di estensione ... Puoi dare un'occhiata ...
Dove implementazione:
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;
}
}
}
Seleziona implementazione:
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 );
}
}
La mia implementazione funziona bene per qualsiasi raccolta ... Ma differisce dai metodi di estensione implementati da Microsoft, perché usano alberi delle espressioni per implementare lo stesso.
In caso di Seleziona è possibile mappare a un IEnumerable di una nuova struttura.
A.Select(x=>new X{UID=x.uid, UNAME=x.uname})
//input as [IEnumerable<A>] --------> return output as [IEnumerable<X> ]
Where () funziona come filtro per IEnumerable, restituirà il risultato sulla base della clausola where.
A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] --------> return output as [IEnumerable<A> ]