Linq: ¿Cuál es la diferencia entre Seleccionar y Dónde?
122
Los métodos Selecty Whereestán disponibles en Linq. ¿Qué debe saber todo desarrollador sobre estos dos métodos? Por ejemplo: cuándo usar uno sobre el otro, las ventajas de usar uno sobre el otro, etc.
No creo que esta pregunta deba marcarse como CW, posiblemente podría tener una respuesta definitiva.
Brandon
1
@Brandon no hay nada de malo en marcar algo CW si es objetivo.
Rex M
@Rex, estoy de acuerdo. Solo digo que la diferencia entre Seleccionar y Dónde tiene una respuesta definitiva, y la segunda parte de la pregunta probablemente se basaría en prácticas comúnmente aceptadas. Solo lo estaba señalando en caso de que el OP no estuviera seguro de marcar cosas como CW. Si él tenía la intención de que fuera CW, entonces está bien para mí.
Brandon
6
Hay mucho de malo en ello. CW es inútil, y lo es más cuando las personas marcan preguntas completamente al azar como CW
jalf
Respuestas:
126
Dónde
encuentra elementos que coinciden y solo devuelve los que sí lo hacen ( filtrado ).
-> IEnumerable<A>adentro, IEnumerable<A>afuera
Seleccione
devuelve algo para todos los elementos de la fuente ( proyección / transformación ). Ese algo pueden ser los elementos en sí mismos, pero por lo general son una proyección de algún tipo.
Selectsiempre devolverá el mismo número de elementos en la lista (independientemente de la condición de filtro que pueda tener). Wherepuede devolver menos elementos dependiendo de la condición de su filtro.
goku_da_master
Y aquí hay un ejemplo de MSDN selecty aquí hay uno parawhere
yazanpro
Al menos para mí, tener algunos antecedentes con otros idiomas, me ayuda a pensar eso Where == filterySelect == map
bgusach
52
Select y Where son dos operadores completamente diferentes que actúan en IEnumerable s.
El primero es lo que llamamos Operador de Proyección , mientras que el último es un Operador de Restricción .
Una forma interesante de tener una idea del comportamiento de dichos operadores es echar un vistazo a su "tipo funcional".
Seleccione: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; toma como entrada tanto un IEnumerable que contiene elementos de tipo T1 como una función que transforma elementos de tipo T1 en elementos de tipo T2. La salida es un IEnumerable que contiene elementos de tipo T2.
A partir de esto, uno puede adivinar fácilmente que este operador producirá su salida aplicando la función de entrada en cada elemento de la entrada IEnumerable y envolviendo los resultados dentro de un nuevo IEnumerable.
El uso de algunos de matemáticas-como notación, que toma como entrada (a, b, c, ...): IEnumerable <T1> y f: T1 → T2 y produce (f (a), f (b), f (c) , ...): IEnumerable <T2>
Donde: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; éste toma un IEnumerable que contiene elementos de tipo T1 y un predicado en T1 (es decir, una función que produce un resultado booleano para una entrada de tipo T1). Verá que la salida también es un IEnumerable que contiene elementos de tipo T1.
Esta vez, uno podría adivinar que un elemento de la entrada IEnumerable estará presente en la salida IEnumerable dependiendo del resultado de la aplicación del predicado al elemento. Agregando a esto la semántica del nombre del operador, puede estar seguro de que producirá la salida IEnumerable tomando de la entrada uno solo aquellos elementos que se evalúan como verdaderos en la aplicación del predicado.
Las personas con experiencia en programación funcional suelen pensar así. ¡Le permite deducir (o al menos adivinar ...) lo que hace un operador solo mirando su tipo!
Como ejercicio, intente observar otros operadores introducidos por LINQ en IEnumerables y deduzca su comportamiento, ¡antes de mirar la documentación!
Seleccione asigna un enumerable a una nueva estructura. Si realiza una selección en un IEnumerable, obtendrá una matriz con la misma cantidad de elementos, pero de un tipo diferente según la asignación que especificó. Donde filtra el IEnumerable para que le proporcione un subconjunto del IEnumerable original.
Si sabe cómo han implementado Dónde y seleccionar métodos de extensión, puede predecir lo que está haciendo ... Traté de implementar dónde y seleccionar métodos de extensión ... Puede echarle un vistazo ...
Donde Implementación:
publicstaticIEnumerable<Tsource>Where<Tsource>(thisIEnumerable<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 )){yieldreturn data;}}}
Seleccionar implementación:
publicstaticIEnumerable<TResult>Select<TSource,TResult>(thisIEnumerable<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)yieldreturnMethod.Invoke( item );}}
Mi implementación funciona bien para cualquier colección ... Pero difiere de los métodos de extensión implementados por Microsoft, porque usan árboles de expresión para implementar lo mismo.
Respuestas:
Dónde
encuentra elementos que coinciden y solo devuelve los que sí lo hacen ( filtrado ).
->
IEnumerable<A>
adentro,IEnumerable<A>
afueraSeleccione
devuelve algo para todos los elementos de la fuente ( proyección / transformación ). Ese algo pueden ser los elementos en sí mismos, pero por lo general son una proyección de algún tipo.
->
IEnumerable<A>
adentro,IEnumerable<B>
afuerafuente
Select
siempre devolverá el mismo número de elementos en la lista (independientemente de la condición de filtro que pueda tener).Where
puede devolver menos elementos dependiendo de la condición de su filtro.select
y aquí hay uno parawhere
Where == filter
ySelect == map
Select y Where son dos operadores completamente diferentes que actúan en IEnumerable s.
El primero es lo que llamamos Operador de Proyección , mientras que el último es un Operador de Restricción .
Una forma interesante de tener una idea del comportamiento de dichos operadores es echar un vistazo a su "tipo funcional".
Seleccione: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; toma como entrada tanto un IEnumerable que contiene elementos de tipo T1 como una función que transforma elementos de tipo T1 en elementos de tipo T2. La salida es un IEnumerable que contiene elementos de tipo T2.
A partir de esto, uno puede adivinar fácilmente que este operador producirá su salida aplicando la función de entrada en cada elemento de la entrada IEnumerable y envolviendo los resultados dentro de un nuevo IEnumerable.
El uso de algunos de matemáticas-como notación, que toma como entrada (a, b, c, ...): IEnumerable <T1> y f: T1 → T2 y produce (f (a), f (b), f (c) , ...): IEnumerable <T2>
Donde: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; éste toma un IEnumerable que contiene elementos de tipo T1 y un predicado en T1 (es decir, una función que produce un resultado booleano para una entrada de tipo T1). Verá que la salida también es un IEnumerable que contiene elementos de tipo T1.
Esta vez, uno podría adivinar que un elemento de la entrada IEnumerable estará presente en la salida IEnumerable dependiendo del resultado de la aplicación del predicado al elemento. Agregando a esto la semántica del nombre del operador, puede estar seguro de que producirá la salida IEnumerable tomando de la entrada uno solo aquellos elementos que se evalúan como verdaderos en la aplicación del predicado.
Las personas con experiencia en programación funcional suelen pensar así. ¡Le permite deducir (o al menos adivinar ...) lo que hace un operador solo mirando su tipo!
Como ejercicio, intente observar otros operadores introducidos por LINQ en IEnumerables y deduzca su comportamiento, ¡antes de mirar la documentación!
fuente
Son distintos:
Select
se trata de transformación .Where
se trata de filtrar .fuente
Seleccione asigna un enumerable a una nueva estructura. Si realiza una selección en un IEnumerable, obtendrá una matriz con la misma cantidad de elementos, pero de un tipo diferente según la asignación que especificó. Donde filtra el IEnumerable para que le proporcione un subconjunto del IEnumerable original.
fuente
Where
~ = FiltroSelect
~ = MapaAmbos retornos
IEnumerable<T>
fuente
Si sabe cómo han implementado Dónde y seleccionar métodos de extensión, puede predecir lo que está haciendo ... Traté de implementar dónde y seleccionar métodos de extensión ... Puede echarle un vistazo ...
Donde Implementación:
Seleccionar implementación:
Mi implementación funciona bien para cualquier colección ... Pero difiere de los métodos de extensión implementados por Microsoft, porque usan árboles de expresión para implementar lo mismo.
fuente
En el caso de Seleccionarlo, puede asignar un IEnumerable de una nueva estructura.
Donde () funciona como un filtro para IEnumerable, devolverá el resultado sobre la base de la cláusula where.
fuente