from consultas c# .net linq list

c# - consultas - Verificando si una lista está vacía con LINQ



select lambda c# list (16)

LINQ en sí mismo debe estar haciendo una optimización seria alrededor del método Count () de alguna manera.

¿Te sorprende esto? Me imagino que para las implementaciones de IList , Count simplemente lee el número de elementos directamente mientras Any tiene que consultar el método IEnumerable.GetEnumerator , crear una instancia y llamar a MoveNext al menos una vez.

/ EDITAR @Matt:

Solo puedo suponer que el método de extensión Count () para IEnumerable hace algo como esto:

Sí, por supuesto que lo hace. Esto es lo que quise decir. En realidad, usa ICollection lugar de IList pero el resultado es el mismo.

¿Cuál es el "mejor" (teniendo en cuenta la velocidad y la legibilidad) para determinar si una lista está vacía? Incluso si la lista es del tipo IEnumerable<T> y no tiene una propiedad Count.

En este momento estoy lanzando 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) deberá visitar cada elemento para devolver el conteo.

Dicho esto, ¿la segunda opción le parece legible? ¿Cual preferirías? ¿O puede 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 comprobación de tiempo de ejecución para usar un conteo 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(); }


@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 optimizarlo llamando al método de extensión Count () para IList<T> .

Solo puedo suponer que el método de extensión Count () para IEnumerable hace algo como esto:

public static int Count<T>(this IEnumerable<T> list) { if (list is IList<T>) return ((IList<T>)list).Count; int i = 0; foreach (var t in list) i++; return i; }

... en otras palabras, un poco de optimización de tiempo de ejecución para el caso especial de IList<T> .

/ EDIT @Konrad +1 compañero: tienes razón en que es más probable que esté en ICollection<T> .


Acabo de escribir una prueba rápida, prueba esto:

IEnumerable<Object> myList = new List<Object>(); Stopwatch watch = new Stopwatch(); int x; watch.Start(); for (var i = 0; i <= 1000000; i++) { if (myList.Count() == 0) x = i; } watch.Stop(); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (var i = 0; i <= 1000000; i++) { if (!myList.Any()) x = i; } watch2.Stop(); Console.WriteLine("myList.Count() = " + watch.ElapsedMilliseconds.ToString()); Console.WriteLine("myList.Any() = " + watch2.ElapsedMilliseconds.ToString()); Console.ReadLine();

El segundo es casi tres veces más lento :)

Al intentar la prueba del cronómetro nuevamente con una pila o matriz u otros escenarios, realmente depende del tipo de lista que parezca, porque demuestran que el recuento es más lento.

¡Así que 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 con otros tipos)


Aquí está mi implementación de la respuesta de Dan Tao, que permite un predicado:

public static bool IsEmpty<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw new ArgumentNullException(); if (IsCollectionAndEmpty(source)) return true; return !source.Any(predicate); } public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) { if (source == null) throw new ArgumentNullException(); if (IsCollectionAndEmpty(source)) return true; return !source.Any(); } private static bool IsCollectionAndEmpty<TSource>(IEnumerable<TSource> source) { var genericCollection = source as ICollection<TSource>; if (genericCollection != null) return genericCollection.Count == 0; var nonGenericCollection = source as ICollection; if (nonGenericCollection != null) return nonGenericCollection.Count == 0; return false; }


Bien, ¿y este?

public static bool IsEmpty<T>(this IEnumerable<T> enumerable) { return !enumerable.GetEnumerator().MoveNext(); }

EDITAR: Me acabo de dar cuenta de que alguien ya ha esbozado esta solución. Se mencionó que el método Any () hará esto, pero ¿por qué no hacerlo usted mismo? Saludos


Este método de extensión funciona para mí:

public static bool IsEmpty<T>(this IEnumerable<T> enumerable) { try { enumerable.First(); return false; } catch (InvalidOperationException) { return true; } }


Esto fue fundamental para que esto funcione con Entity Framework:

var genericCollection = list as ICollection<T>; if (genericCollection != null) { //your code }


Haría una pequeña adición al código que pareciera haber establecido: verifique también para ICollection , ya que esto también lo implementan algunas clases genéricas no obsoletas (es decir, Queue<T> y Stack<T> ). También usaría as lugar de is más idiomático y se ha demostrado que es más rápido .

public static bool IsEmpty<T>(this IEnumerable<T> list) { if (list == null) { throw new ArgumentNullException("list"); } var genericCollection = list as ICollection<T>; if (genericCollection != null) { return genericCollection.Count == 0; } var nonGenericCollection = list as ICollection; if (nonGenericCollection != null) { return nonGenericCollection.Count == 0; } return !list.Any(); }


La segunda opción es mucho más rápida si tiene varios elementos.

  • Any() regresa tan pronto como se encuentra 1 elemento.
  • Count() tiene que seguir revisando toda la lista.

Por ejemplo, supongamos que la enumeración tiene 1000 elementos.

  • Any() verificaría el primero y luego devolvería verdadero.
  • Count() devolverá 1000 después de atravesar toda la enumeración.

Esto es potencialmente peor si usa una de las invalidaciones 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 Enumerable, use la propiedad Cuenta de esa lista.


Otra idea:

if(enumerable.FirstOrDefault() != null)

Sin embargo, me gusta más el enfoque Any ().


Podrías hacer esto:

public static Boolean IsEmpty<T>(this IEnumerable<T> source) { if (source == null) return true; // or throw an exception return !source.Any(); }

Editar : Tenga en cuenta que simplemente usar el método .Count será rápido si la fuente subyacente tiene realmente una propiedad de cuenta rápida. Una optimización válida anterior sería detectar algunos tipos básicos y simplemente usar la propiedad .Count de aquellos, en lugar del método .Any (), pero luego volver a .Any () si no se puede garantizar.


Si compruebo con Count () Linq ejecuta un "SELECT COUNT (*) ..." en la base de datos, pero necesito verificar si los resultados contienen datos, resolví introducir FirstOrDefault () en lugar de Count ();

antes de

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>() if (cfop.Count() > 0) { var itemCfop = cfop.First(); //.... }

Después

var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>() var itemCfop = cfop.FirstOrDefault(); if (itemCfop != null) { //.... }


List.Count es O (1) según la documentación de Microsoft:
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

entonces use List.Count == 0 es mucho más rápido que una consulta

Esto 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 se llama a List.Count no tiene que iterar a través de cada elemento para obtenerlo, simplemente devuelve los datos miembro.


myList.ToList().Count == 0 . Eso es todo


List<T> li = new List<T>(); (li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty;


private bool NullTest<T>(T[] list, string attribute) { bool status = false; if (list != null) { int flag = 0; var property = GetProperty(list.FirstOrDefault(), attribute); foreach (T obj in list) { if (property.GetValue(obj, null) == null) flag++; } status = flag == 0 ? true : false; } return status; } public PropertyInfo GetProperty<T>(T obj, string str) { Expression<Func<T, string, PropertyInfo>> GetProperty = (TypeObj, Column) => TypeObj.GetType().GetProperty(TypeObj .GetType().GetProperties().ToList() .Find(property => property.Name .ToLower() == Column .ToLower()).Name.ToString()); return GetProperty.Compile()(obj, str); }