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.

SBurris
fuente
7
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.

-> IEnumerable<A>adentro, IEnumerable<B>afuera

Drew Noakes
fuente
15
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!

Bruno Reis
fuente
47

Son distintos:

Selectse trata de transformación .

Wherese trata de filtrar .

bruno conde
fuente
18

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.

Steve
fuente
15

Where ~ = Filtro

Select ~ = Mapa

Ambos retornos IEnumerable<T>

Downhillski
fuente
¡ESTO es por lo que vine aquí! ¡Gracias!
Ben Sandeen
7

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:

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;
        }
    }
}

Seleccionar implementación:

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 );
    }
}

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.

Sanu Uthaiah Bollera
fuente
1

En el caso de Seleccionarlo, puede asignar un IEnumerable de una nueva estructura.

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

Donde () funciona como un filtro para IEnumerable, devolverá el resultado sobre la base de la cláusula where.

A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] -------->  return output as [IEnumerable<A> ]
Supriya Bhattacherjee
fuente