private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Digamos que quiero iterar sobre ellos y escribir algo como procesar #n de #m.
¿Hay alguna manera de averiguar el valor de m sin iterar antes de mi iteración principal?
Espero haberme aclarado.
c#
.net
ienumerable
sebagomez
fuente
fuente
El
System.Linq.Enumerable.Count
método de extensión enIEnumerable<T>
tiene la siguiente implementación:Por lo tanto, trata de enviar a
ICollection<T>
, que tiene unaCount
propiedad, y la usa si es posible. De lo contrario, itera.Por lo tanto, su mejor opción es utilizar el
Count()
método de extensión en suIEnumerable<T>
objeto, ya que obtendrá el mejor rendimiento posible de esa manera.fuente
ICollection<T>
primero.T
deIEnumerator<T> enumerator = source.GetEnumerator()
, simplemente se puede hacer esto:IEnumerator enumerator = source.GetEnumerator()
y debe trabajar!IEnumerable<T>
hereda, loIDisposable
que permite que lausing
instrucción lo elimine automáticamente.IEnumerable
no. Así que si usted llamaGetEnumerator
de cualquier manera, usted debe terminar convar d = e as IDisposable; if (d != null) d.Dispose();
Solo agrego información adicional:
La
Count()
extensión no siempre itera. Considere Linq to Sql, donde el recuento va a la base de datos, pero en lugar de recuperar todas las filas, emite elCount()
comando Sql y devuelve ese resultado.Además, el compilador (o tiempo de ejecución) es lo suficientemente inteligente como para llamar al
Count()
método de los objetos si tiene uno. Entonces, no es como dicen otros respondedores, siendo completamente ignorantes y siempre iterando para contar elementos.En muchos casos, el programador solo está verificando el
if( enumerable.Count != 0 )
uso delAny()
método de extensión, ya queif( enumerable.Any() )
es mucho más eficiente con la evaluación diferida de linq, ya que puede causar un cortocircuito una vez que puede determinar que hay elementos. También es más legiblefuente
.Count
propiedad, ya que siempre sabe su tamaño. Al consultarcollection.Count
no hay cálculo adicional, simplemente devuelve el recuento ya conocido. Lo mismo porArray.length
lo que yo sé. Sin embargo,.Any()
obtiene el enumerador de la fuente usandousing (IEnumerator<TSource> enumerator = source.GetEnumerator())
y devuelve verdadero si puede hacerloenumerator.MoveNext()
. Para colecciones:,if(collection.Count > 0)
matrices:if(array.length > 0)
y en enumerablesif(collection.Any())
.IQueryably<T>
aIEnumerable<T>
, no emitirá un recuento de sql. Cuando escribí esto, Linq to Sql era nuevo; Creo que solo estaba presionando para usarAny()
porque para enumerables, colecciones y sql era mucho más eficiente y legible (en general). Gracias por mejorar la respuesta.Un amigo mío tiene una serie de publicaciones en el blog que proporcionan una ilustración de por qué no puedes hacer esto. Crea una función que devuelve un IEnumerable donde cada iteración devuelve el siguiente número primo, hasta el final
ulong.MaxValue
, y el siguiente elemento no se calcula hasta que lo solicite. Pregunta rápida y emergente: ¿cuántos artículos se devuelven?Aquí están las publicaciones, pero son algo largas:
fuente
EnumerableFeatures
objeto) no requeriría que los enumeradores hicieran nada difícil, pero poder hacer tales preguntas (junto con algunas otras como "¿Puede prometerle? devolver siempre la misma secuencia de elementos "," ¿Puede estar expuesto de forma segura al código que no debería alterar su colección subyacente ", etc.) sería muy útil.set yield options
declaración o algo similar para respaldarla. Si se diseña adecuadamente,IEnhancedEnumerator
podría hacer que cosas como LINQ sean mucho más útiles al eliminar muchas "defensivas"ToArray
oToList
llamadas, especialmente ...Enumerable.Concat
se usan para combinar una gran colección que sabe mucho de sí misma con una pequeña que no.IEnumerable no puede contar sin iterar.
En circunstancias "normales", sería posible que las clases que implementan IEnumerable o IEnumerable <T>, como List <T>, implementen el método Count al devolver la propiedad List <T> .Count. Sin embargo, el método Count no es realmente un método definido en la interfaz IEnumerable <T> o IEnumerable. (El único que, de hecho, es GetEnumerator). Y esto significa que no se puede proporcionar una implementación específica de clase.
Más bien, Count es un método de extensión, definido en la clase estática Enumerable. Esto significa que se puede invocar en cualquier instancia de una clase derivada IEnumerable <T>, independientemente de la implementación de esa clase. Pero también significa que se implementa en un solo lugar, externo a cualquiera de esas clases. Lo que, por supuesto, significa que debe implementarse de una manera que sea completamente independiente de las partes internas de estas clases. La única forma de contar es a través de la iteración.
fuente
Alternativamente, puede hacer lo siguiente:
fuente
No, no en general. Un punto en el uso de enumerables es que no se conoce el conjunto real de objetos en la enumeración (de antemano, o incluso en absoluto).
fuente
Puede usar System.Linq.
Obtendrás el resultado '2'.
fuente
Yendo más allá de su pregunta inmediata (que ha sido completamente respondida en forma negativa), si está buscando informar sobre el progreso mientras procesa una enumerable, es posible que desee ver mi publicación de blog Informe de progreso durante las consultas de Linq .
Te permite hacer esto:
fuente
Utilicé tal método dentro de un método para verificar el
IEnumberable
contenido pasadoDentro de un método como este:
fuente
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.Depende de la versión de .Net y la implementación de su objeto IEnumerable. Microsoft ha reparado el método IEnumerable.Count para verificar la implementación, y utiliza ICollection.Count o ICollection <TSource> .Count, vea los detalles aquí https://connect.microsoft.com/VisualStudio/feedback/details/454130
Y a continuación se muestra el MSIL de Ildasm para System.Core, en el que reside System.Linq.
fuente
Aquí hay una gran discusión sobre la evaluación diferida y la ejecución diferida . Básicamente tienes que materializar la lista para obtener ese valor.
fuente
El resultado de la función IEnumerable.Count () puede ser incorrecto. Esta es una muestra muy simple para probar:
El resultado debe ser (7,7,3,3) pero el resultado real es (7,7,3,17)
fuente
La mejor manera que encontré es contar convirtiéndola en una lista.
fuente
Sugeriría llamar a ToList. Sí, está haciendo la enumeración temprano, pero aún tiene acceso a su lista de elementos.
fuente
Es posible que no produzca el mejor rendimiento, pero puede usar LINQ para contar los elementos en un IEnumerable:
fuente
Creo que la forma más fácil de hacer esto.
Referencia: system.linq.enumerable
fuente
Yo uso
IEnum<string>.ToArray<string>().Length
y funciona bien.fuente
IEnum<string>.Count();
"?Uso dicho código, si tengo una lista de cadenas:
fuente