Linq: Qual é a diferença entre Select e Where


122

Os métodos Selecte Whereestão disponíveis no Linq. O que todo desenvolvedor deve saber sobre esses dois métodos? Por exemplo: quando usar um sobre o outro, quaisquer vantagens de usar um sobre o outro, etc.


7
Eu não acho que essa pergunta deva ser marcada como CW, poderia ter uma resposta definitiva.
Brandon

1
@Brandon, não há nada de errado em marcar algo como CW, se for objetivo.
Rex M

@Rex, eu concordo. Apenas dizendo que a diferença entre Select e Where tem uma resposta definitiva, e a segunda parte da pergunta provavelmente se baseará em práticas comumente aceitas. Eu estava apenas apontando no caso de o OP não ter certeza sobre marcar as coisas como CW. Se ele pretendia que fosse CW, tudo bem para mim.
Brandon

6
Há muita coisa errada nisso. CW é inútil, e ficando mais quando as pessoas marcar perguntas completamente ao acaso, como CW
jalf

Respostas:


126

Onde

localiza itens que correspondem e retorna apenas aqueles que correspondem ( filtragem ).

-> IEnumerable<A>dentro, IEnumerable<A>fora

Selecione

retorna algo para todos os itens na fonte ( projeção / transformação ). Que algo pode ser os itens em si, mas geralmente são uma projeção de algum tipo.

-> IEnumerable<A>dentro, IEnumerable<B>fora


15
Selectsempre retornará o mesmo número de elementos na lista (independentemente da condição de filtro que você possa ter). Wherepode retornar menos elementos, dependendo da condição do filtro.
Goku_da_master

E aqui é um exemplo MSDN de selecte aqui é um parawhere
yazanpro

Pelo menos para mim, ter algum fundo com outras línguas, ele ajuda a pensar que Where == filtereSelect == map
bgusach

52

Selecione e Onde estão dois operadores completamente diferentes atuando em IEnumerable s.

O primeiro é o que chamamos de Operador de Projeção , enquanto o último é um Operador de Restrição .

Uma maneira interessante de entender o comportamento desses operadores é dar uma olhada no seu "tipo funcional".

  • Selecione: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; toma como entrada um IEnumerable contendo elementos do tipo T1 e uma função que transforma elementos do tipo T1 em elementos do tipo T2. A saída é um IEnumerable contendo elementos do tipo T2.

    A partir disso, pode-se adivinhar com facilidade que esse operador produzirá sua saída aplicando a função de entrada em cada elemento da entrada IEnumerable e agrupando os resultados dentro de um novo IEnumerable.

    Usando um pouco de matemática-como notação, que toma como entrada (a, b, c, ...): IEnumerable <T1> e f: T1 → T2 e produz (f (a), f (b), f (c) , ...): IEnumerable <T2>

  • Onde: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; este pega um IEnumerable contendo elementos do tipo T1 e um predicado em T1 (ou seja, uma função que produz um resultado booleano para uma entrada do tipo T1). Você vê que a saída também é um IEnumerable contendo elementos do tipo T1.

    Desta vez, seria de supor que um elemento da entrada IEnumerable estará presente na saída IEnumerable, dependendo do resultado da aplicação do predicado ao elemento. Adicionando a isso a semântica do nome do operador, você pode ter certeza de que ele produzirá a saída IEnumerable, retirando da entrada apenas os elementos que são avaliados como verdadeiros na aplicação do predicado.

Pessoas com experiência em programação funcional geralmente pensam assim. Permite deduzir (ou pelo menos adivinhar ...) o que um operador faz apenas olhando seu tipo!

Como exercício, tente examinar outros operadores introduzidos pelo LINQ no IEnumerables e deduzir seu comportamento, antes de examinar a documentação!


47

Eles são distintos:

Selecté tudo sobre transformação .

Whereé tudo sobre filtragem .


18

Selecione mapeia um enumerável para uma nova estrutura. Se você executar uma seleção em um IEnumerable, obterá uma matriz com o mesmo número de elementos, mas um tipo diferente, dependendo do mapeamento especificado. Onde filtra o IEnumerable para fornecer um subconjunto do IEnumerable original.



7

Se você sabe como eles implementaram o Where e selecione os métodos de extensão, você pode prever o que está fazendo ... Tentei implementar o where e selecione os métodos de extensão ... Você pode dar uma olhada nele ...

Onde Implementação ::

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

Selecione a implementação ::

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

Minha implementação funciona bem para qualquer coleção ... Mas difere dos métodos de extensão implementados pela Microsoft, porque eles usam árvores de expressão para implementar o mesmo.


1

No caso de Selecionar, você pode mapear para um IEnumerable de uma nova estrutura.

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

Where () funciona como um filtro para o IEnumerable, ele retornará o resultado com base na cláusula where.

A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] -------->  return output as [IEnumerable<A> ]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.