¿Cuál es la mejor forma (teniendo en cuenta tanto la velocidad como la legibilidad) para determinar si una lista está vacía? Incluso si la lista es de tipo IEnumerable<T>
y no tiene una propiedad Count.
En este momento estoy dando vueltas entre esto:
if (myList.Count() == 0) { ... }
y esto:
if (!myList.Any()) { ... }
Supongo que la segunda opción es más rápida, ya que volverá con un resultado tan pronto como vea el primer elemento, mientras que la segunda opción (para un IEnumerable) necesitará visitar cada elemento para devolver el conteo.
Dicho esto, ¿te parece legible la segunda opción? ¿Cual preferirías? ¿O puedes pensar en una mejor manera de probar una lista vacía?
La respuesta de Edit @ lassevk parece ser la más lógica, junto con un poco de verificación de tiempo de ejecución para usar un recuento en caché si es posible, como este:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
ycast
useas
ynull
verifique:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
equivalente alist.IsEmpty
? El método del marco debe optimizarse: vale la pena escribir uno nuevo solo si descubriste que es un cuello de botella de perf.IsEmpty
método de extensión. github.com/dotnet/corefx/issues/35054 Verifique y vote si lo desea y acepta.Respuestas:
Podrías hacer esto:
Editar : Tenga en cuenta que simplemente usar el método .Count será rápido si la fuente subyacente realmente tiene una propiedad Count rápida. Una optimización válida anterior sería detectar algunos tipos básicos y simplemente usar la propiedad .Count de esos, en lugar del enfoque .Any (), pero luego recurrir a .Any () si no se puede garantizar.
fuente
IsNullOrEmpty()
.return !source?.Any() ?? true;
Haría una pequeña adición al código en el que parece haberse decidido: compruebe también
ICollection
, ya que esto también se implementa incluso en algunas clases genéricas no obsoletas (es decir,Queue<T>
yStack<T>
). También lo usaría enas
lugar deis
porque es más idiomático y se ha demostrado que es más rápido .fuente
NotSupportedException
oNotImplementedException
. La primera vez que usé su código de ejemplo cuando descubrí que una colección que estaba usando arrojó una excepción para Count (quién sabía ...).¿Te sorprende esto? Me imagino que para
IList
implementaciones,Count
simplemente lee el número de elementos directamente mientrasAny
tiene que consultar elIEnumerable.GetEnumerator
método, crear una instancia y llamarMoveNext
al menos una vez./ EDITAR @Matt:
Sí, por supuesto que lo hace. Esto es lo que quise decir. En realidad, usa en
ICollection
lugar deIList
pero el resultado es el mismo.fuente
Acabo de escribir una prueba rápida, prueba esto:
El segundo es casi tres veces más lento :)
Intentar la prueba del cronómetro nuevamente con una pila o matriz u otros escenarios realmente depende del tipo de lista que parece, porque demuestran que Count es más lento.
¡Entonces supongo que depende del tipo de lista que estés usando!
(Solo para señalar, puse más de 2000 objetos en la Lista y el recuento fue aún más rápido, al contrario que otros tipos)
fuente
Enumerable.Count<T>()
Tiene un manejo especial paraICollection<T>
. Si intenta esto con algo más que una lista básica, espero que vea resultados significativamente diferentes (más lentos).Any()
Sin embargo, seguirá siendo el mismo.Enumerable.Any<T>()
paraICollection<T>
? ¿Seguramente el sin parámetros tambiénAny()
podría verificar laCount
propiedadICollection<T>
?List.Count
es O (1) de acuerdo con la documentación de Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
así que solo utilízalo
List.Count == 0
, es mucho más rápido que una consultaEsto se debe a que tiene un miembro de datos llamado Count que se actualiza cada vez que se agrega o elimina algo de la lista, por lo que cuando lo llama
List.Count
no tiene que recorrer cada elemento para obtenerlo, solo devuelve el miembro de datos.fuente
La segunda opción es mucho más rápida si tiene varios elementos.
Any()
vuelve tan pronto como se encuentre 1 artículo.Count()
tiene que seguir revisando toda la lista.Por ejemplo, suponga que la enumeración tenía 1000 artículos.
Any()
comprobaría el primero, luego devolvería verdadero.Count()
devolvería 1000 después de recorrer toda la enumeración.Esto es potencialmente peor si usa una de las anulaciones de predicados: Count () todavía tiene que verificar cada elemento, incluso si solo hay una coincidencia.
Te acostumbras a usar Cualquiera, tiene sentido y es legible.
Una advertencia: si tiene una Lista, en lugar de solo un IEnumerable, use la propiedad Count de esa lista.
fuente
@Konrad lo que me sorprende es que en mis pruebas, paso la lista a un método que acepta
IEnumerable<T>
, por lo que el tiempo de ejecución no puede optimizarla llamando al método de extensión Count ()IList<T>
.Solo puedo suponer que el método de extensión Count () para IEnumerable está haciendo algo como esto:
... en otras palabras, un poco de optimización de tiempo de ejecución para el caso especial de
IList<T>
./ EDIT @Konrad +1 mate: es probable que tengas razón al respecto
ICollection<T>
.fuente
Ok, ¿y qué hay de este?
EDITAR: Me acabo de dar cuenta de que alguien ya ha bosquejado esta solución. Se mencionó que el método Any () hará esto, pero ¿por qué no hacerlo usted mismo? Saludos
fuente
using
bloque, ya que de lo contrario construiste unIDisposable
objeto y luego lo abandonaste. Luego, por supuesto, se vuelve más sucinto cuando utiliza el método de extensión que ya existe y simplemente lo cambia areturn !enumerable.Any()
(que hace precisamente esto).Any()
realiza exactamente eso, por lo que agregar exactamente el mismo método con otro nombre será confuso.Otra idea:
Sin embargo, me gusta más el enfoque Any ().
fuente
Esto fue crítico para que esto funcionara con Entity Framework:
fuente
Si verifico con Count () Linq ejecuta un "SELECT COUNT (*) .." en la base de datos, pero necesito verificar si los resultados contienen datos, decidí introducir FirstOrDefault () en lugar de Count ();
antes de
Después
fuente
fuente
Aquí está mi implementación de la respuesta de Dan Tao, permitiendo un predicado:
fuente
fuente
myList.ToList().Count == 0
. Eso es todofuente
Este método de extensión funciona para mí:
fuente