Qual é a melhor maneira (levando em consideração a velocidade e a legibilidade) para determinar se uma lista está vazia? Mesmo se a lista for do tipo IEnumerable<T>
e não tiver uma propriedade Count.
Agora eu estou jogando entre isso:
if (myList.Count() == 0) { ... }
e isto:
if (!myList.Any()) { ... }
Meu palpite é que a segunda opção é mais rápida, pois retornará com um resultado assim que vir o primeiro item, enquanto a segunda opção (para um IEnumerable) precisará visitar todos os itens para retornar a contagem.
Dito isto, a segunda opção parece tão legível para você? Qual você prefere? Ou você pode pensar em uma maneira melhor de testar uma lista vazia?
A resposta do Edit @ lassevk parece ser a mais lógica, juntamente com um pouco de verificação de tempo de execução para usar uma contagem em cache, se possível, assim:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
ecast
mas o usoas
enull
verificar:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
equivalentelist.IsEmpty
? O método de estrutura deve ser otimizado - vale a pena escrever um novo somente se você descobrir que é um gargalo de desempenho.IsEmpty
método de extensão. github.com/dotnet/corefx/issues/35054 Verifique e vote se quiser e concorda.Respostas:
Você pode fazer isso:
Editar : Observe que o simples uso do método .Count será rápido se a fonte subjacente realmente possuir uma propriedade Count rápida. Uma otimização válida acima seria detectar alguns tipos de base e simplesmente usar a propriedade .Count desses, em vez da abordagem .Any (), mas depois voltar para .Any () se nenhuma garantia puder ser feita.
fonte
IsNullOrEmpty()
.return !source?.Any() ?? true;
Eu faria uma pequena adição ao código no qual você parece ter se estabelecido: verifique também
ICollection
, pois isso também é implementado por algumas classes genéricas não obsoletas (isto é,Queue<T>
eStack<T>
). Eu também usaria, emas
vez deis
ser mais idiomático e mostrar ser mais rápido .fonte
NotSupportedException
ouNotImplementedException
. Eu usei seu exemplo de código pela primeira vez quando descobri que uma coleção que estava usando lançou uma exceção para o Count (quem sabia ...).Isso te surpreende? Eu imagino que, para
IList
implementações,Count
simplesmente leia o número de elementos diretamente enquantoAny
tiver que consultar oIEnumerable.GetEnumerator
método, criar uma instância e chamarMoveNext
pelo menos uma vez./ EDIT @Matt:
Sim, claro que faz. Foi isso que eu quis dizer. Na verdade, ele usa em
ICollection
vez de,IList
mas o resultado é o mesmo.fonte
Acabei de escrever um teste rápido, tente o seguinte:
O segundo é quase três vezes mais lento :)
Se você tentar novamente o cronômetro com uma pilha ou matriz ou outros cenários, isso realmente depende do tipo de lista que parece - porque eles provam que o Count é mais lento.
Então eu acho que depende do tipo de lista que você está usando!
(Apenas para salientar, coloquei mais de 2000 objetos na lista e a contagem foi ainda mais rápida, ao contrário de outros tipos)
fonte
Enumerable.Count<T>()
tem tratamento especial paraICollection<T>
. Se você tentar isso com algo diferente de uma lista básica, espero que você veja resultados significativamente mais lentos.Any()
permanecerá aproximadamente o mesmo, no entanto.Enumerable.Any<T>()
paraICollection<T>
? certamente o sem parâmetrosAny()
poderia apenas verificar aCount
propriedadeICollection<T>
também?List.Count
é O (1) de acordo com a documentação da Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
então use
List.Count == 0
muito mais rápido que uma consultaIsso ocorre porque ele possui um membro de dados chamado Count, que é atualizado sempre que algo é adicionado ou removido da lista; portanto, quando você o chama
List.Count
, não precisa percorrer todos os elementos para obtê-lo, apenas retorna o membro de dados.fonte
A segunda opção é muito mais rápida se você tiver vários itens.
Any()
retorna assim que 1 item é encontrado.Count()
tem que continuar percorrendo a lista inteira.Por exemplo, suponha que a enumeração tenha 1000 itens.
Any()
verificaria o primeiro e depois retornaria verdadeiro.Count()
retornaria 1000 depois de percorrer toda a enumeração.Isso é potencialmente pior se você usar uma das substituições de predicado - Count () ainda precisa verificar todos os itens, mesmo que haja apenas uma correspondência.
Você se acostuma a usar o Any one - faz sentido e é legível.
Uma ressalva - se você tiver uma lista, em vez de apenas um IEnumerable, use a propriedade Count da lista.
fonte
@ Konrad, o que me surpreende é que, em meus testes, estou passando a lista para um método que aceita
IEnumerable<T>
, para que o tempo de execução não possa otimizá-lo chamando o método de extensão Count ()IList<T>
.Só posso assumir que o método de extensão Count () para IEnumerable está fazendo algo parecido com isto:
... em outras palavras, um pouco de otimização de tempo de execução para o caso especial de
IList<T>
./ EDIT @Konrad +1 mate - você está certo sobre a possibilidade de participar
ICollection<T>
.fonte
Ok, e quanto a este?
EDIT: Acabei de perceber que alguém já esboçou esta solução. Foi mencionado que o método Any () fará isso, mas por que não fazer você mesmo? Saudações
fonte
using
bloco, pois, caso contrário, você construiu umIDisposable
objeto e o abandonou. Então, é claro, fica mais sucinto quando você utiliza o método de extensão que já existe e apenas o altera parareturn !enumerable.Any()
(o que faz exatamente isso).Any()
executa exatamente isso, portanto, adicionar exatamente o mesmo método com outro nome será apenas confuso.Outra ideia:
No entanto, eu gosto mais da abordagem Any ().
fonte
Isso foi fundamental para que isso funcionasse com o Entity Framework:
fonte
Se eu verificar com Count (), o Linq executa uma "SELECT COUNT (*) .." no banco de dados, mas preciso verificar se os resultados contêm dados, resolvi introduzir FirstOrDefault () em vez de Count ();
Antes
Depois de
fonte
fonte
Aqui está minha implementação da resposta de Dan Tao, permitindo um predicado:
fonte
fonte
myList.ToList().Count == 0
. Isso é tudofonte
Este método de extensão funciona para mim:
fonte