[Linq] Eficiencia Count() vs. Any()

El tema de la eficiencia se está volviendo importante, siempre lo ha sido, pero ahora más que nunca dado que los Frameworks nos brindan tantas abstracciones que podemos terminar haciendo lo mismo de una u otra forma sin preocuparnos por el que hace de fondo determinada función, y ese es el caso de estas dos sentencias. Dada una lista de la forma:

            List<string> palabras = new List<string>();
            palabras.Add("Primera");
            palabras.Add("Segunda");
            palabras.Add("Tercera");

Podemos entonces comprobar la existencia de elementos de las dos siguiente maneras:

            bool contieneElementosCount = palabras.Count() > 0;
            bool contieneElementosAny = palabras.Any();

Ambas nos devolverán true o false según corresponda, pero lo harán de forma diferente, y aquí es donde debemos empezar a evaluar que no conviene más, por un lado tenemos la función Count() que si miramos la documentación oficial de MSDN veremos que dice claramente, “Si el tipo de source implementa ICollection<T>, esa implementación se utiliza para obtener el recuento de elementos. De lo contrario, este método determina el recuento.” Pero ¿qué quiere decir con esto? Pues simple, si vemos la interfaz ICollection podemos ver que una de sus propiedades es Count, es decir que acudir este método intentara hacer algo como lo siguiente:

            ICollection<string> collection = palabras as ICollection<string>;
            int numeroElementos = collection.Count;

Cosa que para una colección que implementa de ICollection como lo hace List<T> no tiene ningún inconveniente, y como es el caso de todas las colecciones del espacio de nombres de System.Collection.Generic
pues todas implementan de la interfaz genérica ICollection. La excepción no sabría con que colección se presentaría y por lo tanto me parece la más rápida pues solo se debe hacer un casteo [de hecho ni se hace] para obtener el valor de count. El problema radica en que nos arriesgamos a tener una colección que no implemente de este y deba hacer el conteo manual [dentro de un while] y además de preguntar del lado de la linq por n > 0, haces un paso más y te arriesgas el doble.

Por el otro lado tenemos a Any(), este método determina si una secuencia contiene elementos. [*tomado de MSDN] de una forma un poco más directa, acudiendo directamente al método MoveNext de la enumeración pero sin tener que iterar sobre todos ellos, es decir, hará algo como lo siguiente:

            bool contieneElementos;
            using (IEnumerator<string> enumerator = palabras.GetEnumerator())
            {
                contieneElementos = enumerator.MoveNext();
            }

Entonces como podemos ver Any() es un método especialmente diseñado para este propósito y no se debe confundir con una “variación” de Count(), pues su propósito no es ese, si no el de determinar la cantidad de elementos de una colección.

Espero les sea de utilidad.

Hasta el próximo post.

Anuncios
[Linq] Eficiencia Count() vs. Any()

10 comentarios en “[Linq] Eficiencia Count() vs. Any()

  1. Hola Nico,

    Muy buen aporte y sobre todo claro, pero….

    1. Porque si hablas de ICollection no trabajas directamente con la propiedad Count y nunca con el método Count() de IEnumerable, en el caso de ser ICollection siempre te ahorras un Cast: , es decir la propieadad Count está siempre calculada).

    2. Y esto es una pregunta tu cual crees que es más eficiente dado el siguiente escenario.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Entity;
    namespace ConsoleApplication10
    {
    class Program
    {
    static void Main(string[] args)
    {
    using (Contexto ct = new Contexto())
    {
    var resultado = from b in ct.Clientes
    select b;

    var hayelementos = resultado.Count()>0;
    var hayelementosAny = resultado.Any();
    }
    }
    }

    public class Cliente
    {
    public int Id { get; set; }
    public string Nombre { get; set; }
    }

    public class Contexto : DbContext
    {
    public DbSet Clientes { get; set; }
    }
    }

    Saludos:)

    1. Adreas Viklund dijo:

      ZAZ! En Toda la BOCA!

      Pedro, sucede lo mismo cuando usan un filtro como el Where(). Iterator-block, la optimizacion de ICollection es inutil.

      1. Hola @Adreas.

        Optimizacion de ICollection ??… Que optimizacion podria brindar un Icollection ante un Where… :S hasta donde se el metodo de extension where de IEnumerable en su sobrecarga con Func pregunta por el tipo de TSource y acude a sus Iterators dependiendo el tipo de TSource… No se si podrias ser más especifico con tu aprecicación, así aprendemos todos 🙂

        Saludos.

      2. Andreas Viklund dijo:

        Oh, parece que no he tenido en cuenta el XSS del blog, me refiero a ICollection<T> que por si no lo has notado no hereda de ICollection :S usando un filtro como el where o lo que expone Pedro, ya lo has dicho “locos querables” esto ocasiona un bloqueo del iterador en base a la secuencia resultante. Bloquea el iterador.

    2. Hola Pedro.

      1. Vale pues la primera de las peguntas es más por el origen del post, me pille un usuario en MSDN con la duda y la planteaba de esa manera, Y ahora vamos, que trabajando con la abstraccion de ICollection no tienes ni la mitad de excelentes funcionalidades que con una coleccion generica como List, dado que este (ICollection) se implemento para ampliar ciertos comportamientos de IEnumerable, entonces no le veo sentido a sacrificar tanto por tan poco…. Y acudir a su propiedad no te servira en consultas Linq, es decir, en casos como: var hayElementos = palabras.Select(x => x == “Primera”).Count() > 0; o hacer ese odioso casteo.

      2. Esta pregunta si que da para un segundo post 🙂 Y es que te has ido con los locos Querables, que crean sus proios arboles de expresion a partir del TSource para determinar el count y el any y TODO [creo]… aqui el tema es de detallarlo y gracias por la idea 🙂 Ahora estoy tan alejado de los datos que no se me habia ocurrido.

  2. Xavi Paper dijo:

    Entiendo que con esto se puede deducir que si hereda de ICollection es mejor el Count() (ya que es una llamada directa al Count y que supongo que tendrà materializado) y en otra caso es mejor el Any() (Que evita recorrer toda la coleción). No?

    1. Hola.

      Pues vale, con esta pregunta me has pillado y me has hecho caer en cuenta que mi post esta incompleto y que estoy imcompleto y hasta me hiciste llorar 😦 ¿Por que? porque si hay algo que me intriga es saber como se ve toda esta mierda a nivel de procesador y como los sistemas operativos modernos son capaces de manejarlo, y el tema que ahora me intriga y te agradezco por la pregunta, es…. que es mas pesado a nivel de proceso, un casteo o acudir a un metodo?? … como se ve esa cosa a bajo nivel??… quiza Pedro o Adrea me colaberen :S o me tocaria aguantarme las ganas de saber la respuesta hasta el martes 😦 [Estoy de fiestas :P]

      Saludos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s