Find () vs. Where (). FirstOrDefault ()


161

Costumo ver pessoas usando Where.FirstOrDefault()para fazer uma pesquisa e pegar o primeiro elemento. Por que não usar apenas Find()? Existe uma vantagem para o outro? Eu não sabia dizer a diferença.

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}

45
FWIW, list.FirstOrDefault(x => x == "item3");é mais conciso do que usar ambos .Wheree .FirstOrDefault.
— 21412 Kirk Woll

@ Kirk, acho que minha próxima pergunta seria por que eles acrescentaram a descoberta. Essa é uma boa dica. A única coisa em que consigo pensar é que o FirstOrDefault pode retornar um valor padrão diferente de null. Caso contrário, parece apenas uma adição inútil.
— KingOfHypocrites

8
Findé anterior ao LINQ. (estava disponível no .NET 2.0 e você não poderia usar lambdas Você foi forçado a usar métodos normais ou métodos anônimos.)
— Kirk Woll

Respostas:


204

Onde está o Findmétodo IEnumerable<T>? (Questão retórica.)

A Wheree FirstOrDefaultos métodos são aplicáveis contra vários tipos de sequências, incluindo List<T>, T[], Collection<T>, etc. Qualquer sequência que implementa IEnumerable<T>pode utilizar estes métodos. Findestá disponível apenas para o List<T>. Métodos geralmente mais aplicáveis, são mais reutilizáveis e têm maior impacto.

Acho que minha próxima pergunta seria por que eles acrescentaram a descoberta. Essa é uma boa dica. A única coisa em que consigo pensar é que o FirstOrDefault pode retornar um valor padrão diferente de null. Caso contrário, parece apenas uma adição inútil

Findon List<T>antecede os outros métodos. List<T>foi adicionado com genéricos no .NET 2.0 e Findfazia parte da API para essa classe. Wheree FirstOrDefaultforam adicionados como métodos de extensão para o IEnumerable<T>Linq, que é uma versão .NET posterior. Não posso dizer com certeza que, se o Linq existisse com a versão 2.0, isso Findnunca teria sido adicionado, mas esse é sem dúvida o caso de muitos outros recursos que vieram em versões anteriores do .NET que se tornaram obsoletos ou redundantes em versões posteriores.


85
Apenas para complementar: Não há necessidade de chamar Onde e Primeira ou FirstOrDefault: em primeiro ou FirstOrDefault permite que você especifique um predicado de pesquisa, tornando o Onde chamada desnecessária
— Robson Rocha

4
Mas Where(condition).FirstOrDefault()otimiza pelo menos também e, às vezes, melhor do que FirstOrDefault(condition)sozinho. Sempre usamos Where()o desempenho aprimorado quando disponível.
— Suncat2000

7
@ Suncat2000 forneça um exemplo, por favor #
— Konstantin Salavatov

2
@ Suncat2000 Você está usando o Linq devido ao seu poder expressivo e deseja escrever código declarativo. Você não deve se preocupar com essas micro melhorias, que também podem mudar em futuras implementações. Além disso, não otimize muito cedo
— Piotr Falkowski

50

Acabei de descobrir hoje, fazendo alguns testes em uma lista de objetos de 80K e descobri que Find()pode ser até 1000% mais rápido do que usar um Wherecom FirstOrDefault(). Eu não sabia disso até testar um cronômetro antes e depois de cada um. Às vezes era a mesma hora, caso contrário, era mais rápido.


6
Você tentou com Where AND FirstOrDefault? Se você tentou, talvez apenas com FirstOrDefault e veja se Find () ainda é melhor.
— MVCKarl

5
Parece que você não materializou o resultado com uma .ToList()ou .ToArray()para realmente executar a consulta.
— Andrew Morton

4
É porque Findfaz uso das chaves primárias (portanto, índices), enquanto que Whereé uma consulta sql simples
— percebus

4
No EF6, Find e FirstOrDefault geram exatamente as mesmas instruções SQL. Você pode ver o SQL em um aplicativo de console executando context.Database.Log = Console.Write; O exemplo descrito está usando na memória "Localizar" em uma lista de seqüências de caracteres, não indo em um banco de dados com chaves primárias. Talvez a tradução da declaração da cláusula Find - que omite a necessidade de analisar a expressão lambda seja a razão da melhoria de desempenho nesse caso. Em relação a um banco de dados, duvido que você notará uma diferença nas situações de RL ... Também me pergunto se foi testado usando Localizar primeiro em vez de segundo ...
— C.List

2
Bem, esta melhoria de desempenho é porque find () check-in de cache para o objeto antes de bater DB que, no caso () sempre ir DB para obter objeto
— Gaurav

35

Há uma diferença muito importante se a fonte dos dados for Entity Framework: Findencontrará entidades no estado 'adicionado' que ainda não foram persistidas, mas Wherenão serão. Isso é por design.



1

além de Anthony responder à Where()visita através de todos os registros e, em seguida, retornar resultado (s) enquantoFind() não precisar percorrer todos os registros, se o predicado corresponder ao predicado especificado.

digamos que você tenha propriedades ide namepropriedades da classe List of Test .

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

Dará saída de 2, e apenas 2 visitas são necessárias para dar resultado, mas se você usarWhere().FirstOrDefault() , visitaremos todos os registros e obteremos resultados.

Portanto, quando você sabe que deseja apenas o primeiro resultado dos registros na coleção Find(), será mais adequado do queWhere().FirtorDefault();


4
mas se você usar Where (). FirstOrDefault () visitaremos todos os registros e obteremos resultados. Não. FirstOrDefault'borbulha' a cadeia e para de enumerar tudo. Uso o termo 'bolha' por falta de uma expressão melhor, porque na verdade todos os seletores / predicados serão passados ​​para o próximo, portanto, o último método da cadeia está realmente trabalhando primeiro.
— Silvermind

1

Uau, acabei de assistir ao tutorial da EF no MicrosofToolbox hoje no Youtube. Ele disse sobre o uso de Find () e FirstOrDefault (condição) na consulta e Find () procurará os dados que você executou algo nesse objeto (adicionar ou editar ou excluir - mas ainda não salvos no banco de dados) enquanto o FirstOrDefault apenas procure o que já foi salvo


-1

Find()é o equivalente IEnumerable de a FirstOrDefault(). Você não deve encadear os dois .Where () .FirstOrDefault()porque ele .Where()passa por toda a matriz e, em seguida, percorre a lista para encontrar o primeiro item. Você economiza uma quantidade incrível de tempo colocando seu predicado de pesquisa no FirstOrDefault()método.

Além disso, incentivo você a ler a pergunta vinculada a este tópico para saber mais sobre os melhores desempenhos no uso de .Find()cenários específicos. Desempenho de Find () vs. FirstOrDefault ()


Esta é uma duplicata da resposta acima da sua. Veja também o comentário de Silvermind sobre essa resposta.
— carlin.scott 15/01
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.