¿De qué sirve .Any () en una lista de C # <>?

40

He estado discutiendo esto con colegas, y no pudimos averiguar cuál es el uso de .Anyun determinado List<>, en C #.

Puede verificar la validez de un elemento en la matriz como la siguiente declaración:

if (MyList.Any()){ ...}  //Returns true or false

Que es exactamente lo mismo que

if (MyList.Count() != 0) { ... }

y es mucho más común, legible y claro sobre la intención de la ifdeclaración.

Al final, nos quedamos atrapados con este pensamiento:

.Any() puede usarse, funcionará igual de bien, pero es menos claro acerca de la intención del programador y, en ese caso, no debe usarse.

Pero sentimos que esto no puede ser correcto; Debemos estar perdiendo algo.

¿Estamos?

Gil Sand
fuente
40
¿De qué manera es menos clara la intención?
jk.
35
Desafío su afirmación que Any()es menos clara: me Any()parece más clara, especialmente con una condición lambda. Traducir el código al inglés en mi cabeza, se if(MyList.Count(o => o > 10) > 0)convierte en "¿Es el número de elementos mayor que 10 más que 0?" mientras que se if(MyList.Any(o => o > 10))convierte en "¿Hay algún elemento mayor que 10?"
BlueRaja - Danny Pflughoeft
3
@SargeBorsch: solo si prefiere Heskel / nomenclatura funcional, que la mayoría de la gente no.
Davor Ždralo
44
@ BlueRaja-DannyPflughoeft estoy de acuerdo. Creo que cualquiera está más claro, ya que elimina un lo que podría considerarse un número mágico.
Andy
2
@SargeBorsch: el SQL paralelo a Anyes Exists. El nombre de Linq probablemente esté más inspirado en Haskell y Python, que también tienen alguna / todas las funciones.
JacquesB

Respuestas:

95

Tenga en cuenta que Anyno funciona en un List; opera en un IEnumerable, que representa un tipo concreto que puede o no tener una Countpropiedad. Es cierto que no es necesariamente lo mejor para usar en un List, pero definitivamente es útil al final de una consulta LINQ. Y aún más útil que la versión independiente es la anulación que toma un predicado igual que Where. No hay nada incorporado Listque sea tan conveniente o expresivo como el Anymétodo de extensión del predicado .

Además, si está utilizando Count()(el método de extensión LINQ para IEnumerable), en lugar de Count(la propiedad en List), puede tener que enumerar toda la secuencia si no puede optimizar esto al detectar que su tipo de datos subyacente tiene una CountPropiedad . Si usted tiene una secuencia larga, esto puede ser un impacto de rendimiento notable cuando realmente no se preocupan por lo que el recuento es, y sólo quieren saber si hay alguna elementos de la colección.

Mason Wheeler
fuente
19
Esta. Dejando de lado el rendimiento, Any()con un predicado es más expresivo que comparar la anulación de Enumerable.Count()eso toma un predicado con 0. :)
Dan J
1
Creo que esto explica los fundamentos tan claramente que explica la respuesta en el mejor de los casos.
Tarik
2
En mi humilde opinión, Existses tan conveniente y expresivo como Any, con un predicado. Usar Count != 0propiedad en a Listes más normal que usar Any(). Es solo preferencia personal. También he pasado por el esfuerzo de cambiar _list_.Count()a _list_.Counten el código de mi grupo. Hizo una diferencia notable para mí.
Suncat2000
55

Hay una diferencia de tiempo de ejecución que Count()puede ser O (n) donde Any()es O (1).

Firmar
fuente
15
Count()tampoco se detendrá por iteradores infinitos, mientras que Any()sí, ya que solo necesita llamar MoveNext()una vez.
Jon Purdy
3
Breve y preciso, pero esto se lee más como un comentario que como una respuesta. Los programadores prefieren respuestas que profundicen en el por qué y proporcionen una medida de explicación. Considere editar su respuesta y ampliar por qué O (1) podría ser (es) importante.
muy buena respuesta, acabo de enterarme que debería usar any en lugar de count == 0: d
MonsterMMORPG
44
Any(Func<T>)is O (n)
BlueRaja - Danny Pflughoeft
1
En el caso específico de List, el rendimiento es el mismo porque la extensión usa la propiedad. Verdadero para todas las colecciones que implementan la ICollectioninterfaz.
Thorkil Holm-Jacobsen
9

En realidad, tenga en cuenta que existe la propiedad List.Count , y luego está el método Enumerable.Count .

En su ejemplo, está utilizando el Enumerable.Count()método, que tiene que recorrer cada elemento de la enumeración para obtener un resultado. Eso es claramente más lento que llamar, Any()que solo necesita iterar sobre el primer elemento, si existe.

EDITAR:

En los comentarios se señaló, con razón, que el Enumerable.Count()método de extensión no necesita iterar a través de todos los elementos si detecta que el enumerable también es un ICollection<T>. Entonces, en el caso de a List<T>, el uso de la Countpropiedad o el método en realidad no hace la diferencia.

Fuente IEnumerable.Count :

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}
Sstan
fuente
Lo suficientemente justo. ¿Qué pasa con el uso de la propiedad .Count entonces? ¿no haría eso que la lectura fuera significativamente más rápida, tal vez tan rápida o incluso más rápida que llamar a .Any ()?
Gil Sand
44
Con un List<T>la diferencia de rendimiento será insignificante. Así que solo usa lo que prefieras. Pero para otros tipos de IEnumerables, solo puede elegir entre Count()(el método) y Any(), en ese caso, Any()siempre será el claro ganador para su caso de uso y debería preferirse. Por lo que vale, creo que Any()es bastante legible y claro.
sstan
@sstan sí, a menos que si lo innumerable se pueda lanzar a una colección, entonces se puede optimizar y no importará.
Esben Skov Pedersen
2
Count()tiene la misma complejidad que Countpara ICollections, ya que el método de extensión utiliza la propiedad en lugar de iterar.
Thorkil Holm-Jacobsen
Las extensiones de Linq están optimizadas para interfaces conocidas: IList, ICollection. La discusión sobre el rendimiento aquí es totalmente redundante, incluso si eso es un detalle de implementación
Gusdor
6

Una pregunta sorprendente: encuentro que la intención de list.Any()ser mucho más clara que la intención de list.Count()!=0.

Intención significa: si lees el código de alguien (y no lo escribiste tú mismo), ¿es completamente obvio lo que el programador quiere lograr y por qué lo escribió escrito así? Si un problema común se resuelve de una manera innecesariamente compleja, inmediatamente sospecha y se pregunta por qué el desarrollador no usó la forma simple. Miras el código e intentas ver si te has perdido algo. Tiene miedo de cambiar el código porque le preocupa que haya algún efecto secundario que le falte y cambiarlo puede causar problemas inesperados.

La intención de usar el Any()método es completamente clara: desea saber si hay elementos en la lista o no.

La intención de la expresión, Count()!=0por otro lado, no es obvia para el lector. Por supuesto, no es difícil ver que la expresión te dice si la lista está vacía o no. Las preguntas surgen porque lo escribes de esta manera particular en lugar de usar el método estándar. ¿Por qué lo usas Count()explícitamente? Si realmente sólo necesita saber si hay alguna elementos de una lista, ¿por qué desea contar toda la lista en primer lugar? Tan pronto como llegue a 1, ya tiene su respuesta. Si la fuente era un iterador sobre una colección grande (quizás infinita) o se traduce a sql, podría hacer una gran diferencia en cuanto al rendimiento. Entonces, ¿tal vez el uso explícito de Count () es forzar una consulta diferida para ejecutar o recorrer un iterador?

Pero la fuente es en realidad un lugar List<T>donde Count()está O (1) y no tiene efectos secundarios. Pero si el código se basa en esta propiedad de List<T>, ¿por qué no utilizar la Countpropiedad -que indica más claramente que espera una operación O (1) sin efectos secundarios?

Como está escrito, list.Count()!=0hace exactamente lo mismo, list.Any()excepto que es innecesariamente más complejo y la intención no está clara.

JacquesB
fuente
Leí ambas cosas como "¿contiene la lista algún elemento?" Count()tiene una conversión implícita que evitaría usar, pero no está claro. El compilador puede optimizarlo, lo que solo hace que la codificación sea descuidada.
Suncat2000
2

Tal vez es solo la palabra? Anyes un adjetivo, en realidad no dice nada. Viniendo de Java, lo llamaría isNonEmptyque contiene un verbo. Un chico SQL podría preferir EXISTS. Pero quizás Anyencaja mejor en el sistema C #.

Cualquiera sea la palabra que elija, una vez que se acostumbre a ella, debe ser mucho más clara. ¿Preguntarías " more than zeroquedan botellas de cerveza"? ¿Esperarías que las one or morepersonas empiecen a contarlos antes de que respondan "No, no hay any"?

maaartinus
fuente
1
El nombre "cualquiera" tiene sentido cuando lo piensas en términos de LINQ: Any()es realmente un atajo paraAny(o => true)
BlueRaja - Danny Pflughoeft
Normalmente no usaría vacío para describir si un enumerable tenía algo para enumerar. Sin embargo, "¿hay alguna cosa para enumerar" me parece natural, y cualquier obra contra cualquier enumeración.
Andy