private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Digamos que eu queira iterar nelas e escrever algo como processar #n de #m.
Existe uma maneira de descobrir o valor de m sem iterar antes da minha iteração principal?
Espero ter me esclarecido.
c#
.net
ienumerable
sebagomez
fonte
fonte
O
System.Linq.Enumerable.Count
método de extensão onIEnumerable<T>
tem a seguinte implementação:Por isso, tenta converter para
ICollection<T>
, que possui umaCount
propriedade, e a usa, se possível. Caso contrário, ele itera.Portanto, sua melhor aposta é usar o
Count()
método de extensão em seuIEnumerable<T>
objeto, pois assim você obterá o melhor desempenho possível.fonte
ICollection<T>
primeiro.T
emIEnumerator<T> enumerator = source.GetEnumerator()
, simplesmente você pode fazer isso:IEnumerator enumerator = source.GetEnumerator()
e deve funcionar!IEnumerable<T>
herda, oIDisposable
que permite que ausing
declaração a descarte automaticamente.IEnumerable
não. Então, se você chamarGetEnumerator
qualquer forma, você deve terminar comvar d = e as IDisposable; if (d != null) d.Dispose();
Apenas adicionando algumas informações extras:
A
Count()
extensão nem sempre itera. Considere Linq to Sql, onde a contagem vai para o banco de dados, mas em vez de retornar todas as linhas, ele emite oCount()
comando Sql e retorna esse resultado.Além disso, o compilador (ou tempo de execução) é inteligente o suficiente para chamar o
Count()
método de objetos se tiver um. Portanto, não é como os outros respondentes dizem, sendo completamente ignorante e sempre iterando para contar elementos.Em muitos casos em que o programador está apenas checando
if( enumerable.Count != 0 )
usando oAny()
método de extensão,if( enumerable.Any() )
é muito mais eficiente com a avaliação preguiçosa do linq, pois pode causar um curto-circuito quando determinar que existem elementos. Também é mais legívelfonte
.Count
propriedade, pois ela sempre sabe o tamanho. Ao consultarcollection.Count
não há computação adicional, ele simplesmente retorna a contagem já conhecida. MesmoArray.length
até onde eu sei. No entanto,.Any()
obtém o enumerador da fonte usandousing (IEnumerator<TSource> enumerator = source.GetEnumerator())
e retorna true, se puderenumerator.MoveNext()
. Para coleçõesif(collection.Count > 0)
:, matrizes:if(array.length > 0)
e em enumeráveis, façaif(collection.Any())
.IQueryably<T>
em a,IEnumerable<T>
ele não emitirá uma contagem de sql. Quando escrevi isso, o Linq to Sql era novo; Eu acho que estava pressionando para usar,Any()
porque para enumeráveis, coleções e sql era muito mais eficiente e legível (em geral). Obrigado por melhorar a resposta.Um amigo meu tem uma série de postagens no blog que fornecem uma ilustração do motivo pelo qual você não pode fazer isso. Ele cria uma função que retorna um IEnumerable em que cada iteração retorna o próximo número primo, até o fim
ulong.MaxValue
, e o próximo item não é calculado até que você o solicite. Pergunta rápida e pop: quantos itens são devolvidos?Aqui estão as postagens, mas são longas:
fonte
EnumerableFeatures
objeto) não exigiria que os enumeradores fizessem algo difícil, mas seria capaz de fazer essas perguntas (junto com outros como "Você pode prometer sempre retorne a mesma sequência de itens "," Você pode ser exposto com segurança a códigos que não devem alterar sua coleção subjacente "etc.) seria muito útil.set yield options
declaração ou algo semelhante para apoiá-lo. Se projetado corretamente, umIEnhancedEnumerator
poderia fazer coisas como LINQ muito mais útil, eliminando um monte de "defensiva"ToArray
ouToList
chamadas, especialmente ...Enumerable.Concat
são usadas para combinar uma coleção grande que sabe muito sobre si mesma com uma coleção pequena que não sabe.IEnumerable não pode contar sem iterar.
Em circunstâncias "normais", seria possível para as classes que implementam IEnumerable ou IEnumerable <T>, como List <T>, implementar o método Count retornando a propriedade List <T> .Count. No entanto, o método Count não é realmente um método definido na interface IEnumerable <T> ou IEnumerable. (O único que é, de fato, é GetEnumerator.) E isso significa que não é possível fornecer uma implementação específica de classe.
Em vez disso, Count é um método de extensão, definido na classe estática Enumerable. Isso significa que pode ser chamado em qualquer instância de uma classe derivada IEnumerable <T>, independentemente da implementação dessa classe. Mas também significa que é implementado em um único local, externo a qualquer uma dessas classes. O que, é claro, significa que deve ser implementado de maneira completamente independente dos internos dessas classes. A única maneira de fazer a contagem é através da iteração.
fonte
Como alternativa, você pode fazer o seguinte:
fonte
Não, não em geral. Um ponto no uso de enumeráveis é que o conjunto real de objetos na enumeração não é conhecido (antecipadamente ou mesmo).
fonte
Você pode usar o System.Linq.
Você obterá o resultado '2'.
fonte
Indo além da sua pergunta imediata (que foi totalmente respondida em negativo), se você estiver procurando relatar o progresso enquanto processa um enumerável, consulte a minha postagem no blog Relatando o progresso durante as consultas Linq .
Permite fazer isso:
fonte
Eu usei dessa maneira dentro de um método para verificar o
IEnumberable
conteúdo passadoDentro de um método como este:
fonte
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.Depende da versão do .Net e da implementação do seu objeto IEnumerable. A Microsoft corrigiu o método IEnumerable.Count para verificar a implementação e usa o ICollection.Count ou ICollection <TSource> .Count, consulte os detalhes aqui https://connect.microsoft.com/VisualStudio/feedback/details/454130
E abaixo está o MSIL da Ildasm para System.Core, no qual o System.Linq reside.
fonte
Aqui está uma ótima discussão sobre avaliação lenta e execução adiada . Basicamente, você precisa materializar a lista para obter esse valor.
fonte
O resultado da função IEnumerable.Count () pode estar errado. Esta é uma amostra muito simples para testar:
O resultado deve ser (7,7,3,3), mas o resultado real é (7,7,3,17)
fonte
A melhor maneira que encontrei é contar convertendo-o em uma lista.
fonte
Eu sugeriria chamar a ToList. Sim, você está fazendo a enumeração antecipada, mas ainda tem acesso à sua lista de itens.
fonte
Pode não produzir o melhor desempenho, mas você pode usar o LINQ para contar os elementos em um IEnumerable:
fonte
Eu acho que a maneira mais fácil de fazer isso
Referência: system.linq.enumerable
fonte
Eu uso
IEnum<string>.ToArray<string>().Length
e funciona bem.fonte
IEnum<string>.Count();
"?Eu uso esse código, se eu tiver uma lista de strings:
fonte