Sentencias en LINQ (VIII): Cuantificadores, generadores y conversores


Hasta ahora hemos visto las operaciones más comunes que pueden realizarse mediante LINQ. Por lo tanto, sólo nos queda echarle un vistazo a un subconjunto de sentencias de carácter más auxiliar, tales como la cuantificación, generación y conversión de elementos.

Any

El método Any toma como argumento un delegado o expresión lambda que tomará como parámetro un elemento de la lista y devolverá un valor booleano que indicará si al menos un elemento de la lista cumple la condición especificada.

Así, si quisiéramos saber si se ha vendido al menos un producto cuyo ID sea 3, podríamos optar por, bien crear un método que realice la comparación y que será pasado como delegado, bien utilizar una expresión lambda que realice la misma operación.


        // OPCIÓN 1: Usamos un delegado de una función que toma un elemento del listado como parámetro
        // y devuelve un booleano que devuelve el resultado de la comparación
        public bool PedidoConProductoIgualA3(LineaPedido linea)
        {
            return linea.IdProducto == 3;
        }
        bool existe = DataLists.ListaLineasPedido.Any(PedidoConProductoIgualA3);

        // OPCIÓN 2: Usamos una expresión lambda que realice la misma operación
                  bool existe = DataLists.ListaLineasPedido.Any(linea => (linea.IdProducto == 3));

Es posible usar este método también en agrupaciones. Por ejemplo, si quisiéramos recuperar los pedidos que contengan una línea de pedido asociada al producto con ID=3, haríamos algo similar a lo anterior, pero utilizando el método Any en la agrupación.


            var consulta = from linea in DataLists.ListaLineasPedido
                           group linea by linea.IdPedido into grupoPedido
                           where grupoPedido.Any(lineaPedido => (lineaPedido.IdProducto == 3))
                           select new
                           {
                               IdPedido = grupoPedido.Key,
                               LineasPedido = grupoPedido
                           };

            foreach (var pedido in consulta)
            {
                Console.WriteLine(string.Format("Pedido: {0}", pedido.IdPedido));
                foreach (var lineaPedido in pedido.LineasPedido)
                {
                    Console.WriteLine(string.Format("\tID: {0}\tPRODUCTO: {1}\tCANTIDAD: {2}",
                        lineaPedido.Id, lineaPedido.IdProducto, lineaPedido.Cantidad));
                }
            }

All

Si, por el contrario, lo que queremos comprobar es si todos los miembros de un conjunto cumplen una propiedad, haremos uso del método All, cuya sintaxis es similar al método Any. Así, si quisiéramos comprobar que todas las líneas de pedido tienen asociado más de un producto, bastaría con codificar lo siguiente:


         bool resultado = DataLists.ListaLineasPedido.All(linea => (linea.Cantidad > 0));

Range

LINQ también proporciona un conjunto de métodos que permiten generar datos. Por ejemplo, Range es capaz de generar una secuencia de datos a partir de un número inicial y un número de elementos. El siguiente método generará un listado con mil enteros:


            var numeros = Enumerable.Range(1, 1000);

            foreach (int numero in numeros)
            {
                Console.Write(string.Format("{0} ", numero));
            }

Repeat

Otro modo de generar datos es mediante el método Repeat. Éste es capaz de crear un listado con n copias de un mismo objeto. Por ejemplo:


            Cliente cliente = DataLists.ListaClientes[0];
            var repeticion = Enumerable.Repeat(cliente, 10);
            foreach (var c in repeticion)
            {
                Console.WriteLine(string.Format("ID: {0}\tNOMBRE: {1}",
                    c.Id, c.Nombre));
            }

Esto hará que generemos un listado compuesto por el objeto cliente repetido 10 veces.

ToArray y ToList

Estos métodos convierten una secuencia en un array cuyo tipo se corresponde con el tipo contenido en la propia secuencia y en un objeto de la clase List<T>, siendo T el tipo contenido en la secuencia. Su uso no es muy complicado.

Además, la ejecución de alguno de estos métodos conlleva un efecto colateral: la ejecución inmediata de la consulta (recordemos que la declaración de la sentencia LINQ no provoca su ejecución, sino que ésta es ejecutada en el momento en el que se utiliza).


            var consulta = from producto in DataLists.ListaProductos
                           select producto;

            Producto[] arrayProductos = consulta.ToArray();
            List<Producto> listaProductos = consulta.ToList();

ToDictionary

El método ToDictionary es capaz de generar un objeto de la clase Dictionary<TKey, TElement>, en el que el primer elemento se correspondería con la clave y el segundo elemento, con el objeto en sí. El siguiente ejemplo generará un diccionario en el que la clave se corresponde con el identificador del producto y el valor, con el producto en sí. Para ello, nuevamente, haremos uso de expresiones lambda.


            Dictionary<int, Producto> diccionarioProductos = consulta.ToDictionary(producto => producto.Id);

            foreach (int clave in diccionarioProductos.Keys)
            {
                Console.WriteLine(string.Format("ID: {0}\tPRODUCTO:{1}",
                    clave, diccionarioProductos[clave].Descripcion));
            }

Recordemos que, en un diccionario, la clave tiene que ser única. El resultado del siguiente código será el siguiente:

OfType

Por último, el método OfType devolverá aquellos elementos del tipo indicado.


            // Obtenemos los productos
            var consultaProductos = from producto in DataLists.ListaProductos
                                    select producto;
            // Obtenemos los clientes
            var consultaClientes = from cliente in DataLists.ListaClientes
                                    select cliente;

            // Creamos un array que contendrá productos y clientes
            var consulta = ((object[])consultaProductos.ToArray()).
                Union((object[])consultaClientes.ToArray());

            // Extraemos los productos del array anterior
            var soloProductos = consulta.OfType<Producto>();

            foreach(var elemento in soloProductos)
            {
                Console.WriteLine(string.Format("ID: {0}\tPRODUCTO: {1}",
                    elemento.Id, elemento.Descripcion));
            }

En el ejemplo obtenemos dos conjuntos: uno de productos y otro de clientes. A continuación convertimos el primer conjunto en un array de objetos (object[]) mediante el método ToArray() y a continuación le añadimos (mediante Union) los elementos del segundo conjunto, que también convertimos previamente en array.

A continuación, mediante OfType(), filtramos aquellos objetos cuyos elementos sean de la clase Producto.

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