OPERACIONES SOBRE CONJUNTOS
Las listas generadas mediante el álgebra
relacional no son, en última instancia, más que conjuntos de datos. Y si nos
ceñimos a una definición formal de conjunto, tenemos que se trata de una
agrupación de elementos que es, a su vez, un elemento.
Sobre estos conjuntos pueden realizarse
una serie de operaciones básicas:
§ Distinción: selección de los
elementos del conjunto que no son iguales a ningún otro.
§ Unión: creación de un conjunto
a partir de los elementos de dos o más conjuntos, sin tener en cuenta los
elementos repetidos.
§ Concatenación: similar a la unión,
pero teniendo en cuenta los elementos repetidos.
§ Comparación: comprueba si los
conjuntos poseen exactamente los mismos elementos.
§ Intersección: creación de un conjunto
a partir de los elementos comunes a dos o más conjuntos.
§ Diferencia: creación de un conjunto
a partir de los elementos de un conjunto cuyos elementos NO se encuentran en
otro conjunto.
La operación de distinción (Distinct) la
hemos visto en artículos anteriores, por lo que nos centraremos en el resto de
operaciones. Comenzaremos por realizar tres consultas compuestas. Una de ellas
contendrá información sobre las compras realizadas con valor superior a 20
euros. Otra contendrá las compras por valor entre 7 y 22 euros. La tercera
contendrá información sobre compras con valor inferior a 10 euros.
Para ello, generaremos una consulta
genérica que realice la agrupación y, a partir de esta, tres consultas más que
apliquen los filtros deseados a la primera:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var consulta = from linea in DataLists.ListaLineasPedido join producto in DataLists.ListaProductos on linea.IdProducto equals producto.Id group new { linea, producto } by linea.IdPedido
into grupoLineaProducto select new { IdPedido
= grupoLineaProducto.Key, ValorTotal
= grupoLineaProducto.Sum(lineaProducto => lineaProducto.linea.Cantidad *
lineaProducto.producto.Precio) }; var consulta1 =
consulta.Where(elemento => elemento.ValorTotal > 20); var consulta2 =
consulta.Where(elemento => ((elemento.ValorTotal > 7) && (elemento.ValorTotal < 22))); var consulta3 =
consulta.Where(elemento => elemento.ValorTotal < 10); |
El resultado de iterar sobre estos tres conjuntos será el siguiente:
Una vez tenemos tres conjuntos (sets) de
datos, ya podemos empezar a realizar operaciones con ellos.
Union
La unión de conjuntos crea un conjunto a
partir de los elementos de dos o más conjuntos. Se realiza mediante el
método Union, que recibirá un conjunto como parámetro.
Así, la unión de los tres conjuntos se
realizará mediante el siguiente código:
1 |
var consultaUnion =
consulta1.Union(consulta2).Union(consulta3); |
El resultado de la operación será el
siguiente:
Como podemos observar,
la unión de los conjuntos proporciona un nuevo conjunto compuesto por los
elementos de los conjuntos ignorando los elementos repetidos.
Por lo tanto ¿cómo
podríamos hacer para unir los conjuntos anteriores respetando todos sus
elementos? Es decir, ¿cómo permitir elementos repetidos dentro de una unión?
Para realizar esta operación no usaremos la unión, sino la concatenación.
Como podemos observar,
la unión de los conjuntos proporciona un nuevo conjunto compuesto por los
elementos de los conjuntos ignorando los elementos repetidos.
Por lo tanto ¿cómo
podríamos hacer para unir los conjuntos anteriores respetando todos sus
elementos? Es decir, ¿cómo permitir elementos repetidos dentro de una unión?
Para realizar esta operación no usaremos la unión, sino la concatenación.
Concat
La concatenación realiza
una unión completa de dos conjuntos, sin eliminar los elementos duplicados que
están presentes en más de un conjunto. Su sintaxis es la siguiente:
1 |
var consultaConcat =
consulta1.Concat(consulta2).Concat(consulta3); |
Como vemos, el resultado
es similar al de la unión, salvo por la presencia de elementos duplicados
(pedidos número 2 y 5)
SequenceEqual
Es posible comparar los
elementos de una consulta a partir de los elementos y del orden que esta posee,
es decir, comprobando que se trata de dos secuencias iguales. Así, las
siguientes dos consultas tendrán, teóricamente, los mismos elementos pero en distinto
orden, mientras que la tercera consulta tendrá los mismos elementos que la
primera:
1 2 3 |
var consultaUnion1 =
consulta1.Union(consulta2); var consultaUnion2 =
consulta2.Union(consulta1); var consultaUnion3 = consulta1.Union(consulta2).Union(consulta1); |
El método SequenceEqual devolverá true si
los elementos son iguales y se encuentran en el mismo orden, y devolverá false en
caso contrario:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
foreach (var elemento in consultaUnion1) { Console.WriteLine(string.Format("ID
PEDIDO: {0}\tVALOR:{1}", elemento.IdPedido,
elemento.ValorTotal)); } Console.WriteLine("--------------------------------------------------"); foreach (var elemento in consultaUnion2) { Console.WriteLine(string.Format("ID
PEDIDO: {0}\tVALOR:{1}", elemento.IdPedido,
elemento.ValorTotal)); } Console.WriteLine("--------------------------------------------------"); foreach (var elemento in consultaUnion3) { Console.WriteLine(string.Format("ID
PEDIDO: {0}\tVALOR:{1}", elemento.IdPedido,
elemento.ValorTotal)); } Console.WriteLine(string.Format("Son
iguales los conjuntos 1 y 2? {0}", consultaUnion1.SequenceEqual(consultaUnion2)
? "Sí" :
"No")); Console.WriteLine(string.Format("Son
iguales los conjuntos 2 y 3? {0}", consultaUnion2.SequenceEqual(consultaUnion3)
? "Sí" :
"No")); Console.WriteLine(string.Format("Son
iguales los conjuntos 1 y 3? {0}", consultaUnion1.SequenceEqual(consultaUnion3)
? "Sí" :
"No")); |
El resultado muestra que
sólo las secuencias 1 y 3 son iguales, pese a que los tres conjuntos poseen los
mismos elementos:
Intersect
La intersección de dos
conjuntos devolverá como resultado un nuevo conjunto con los elementos que
se encuentren en ambos conjuntos. Así, si realizamos la intersección de los dos
primeros conjuntos:
1 2 |
var consultaInterseccion1 =
consulta1.Intersect(consulta2); var consultaInterseccion2 =
consulta2.Intersect(consulta3); |
Los resultados serán los
elementos comunes, es decir:
Como podemos ver, los
conjuntos 1 y 2 comparten el pedido 2. Los conjuntos 2 y 3 tienen tan sólo en
común el pedido 5. Si realizásemos la intersección entre los conjuntos 1 y 3,
el conjunto resultante resultaría vacío, ya que no poseen elementos en común.
Except
La diferencia de dos
conjuntos dará como resultado aquellos elementos del primer conjunto (ojo: sólo del
primer conjunto) que no se encuentren en el segundo. Así, si el
primer conjunto tiene los elementos (1, 2) y el segundo tiene los elementos (2,
3, 4, 5, 6, 7, 8, …, 1000), la diferencia del primero respecto al segundo serán
aquellos elementos del primero que no se encuentran en el segundo, es decir
(1), ya que el elemento 2 sí que pertenece al segundo conjunto.
A diferencia de la unión
y la intersección, esta operación no es conmutativa, por lo que hay que
tener cuidado con el orden en el que se aplica. Así, la diferencia entre el
primer conjunto y el segundo se calculará mediante el siguiente código:
1 |
var consultaDiferencia1 =
consulta1.Except(consulta2); |
El cual dará lugar al siguiente
resultado:
Como podemos ver, el
pedido 2 pertenecía tanto al primer conjunto como al segundo, por lo que el
resultado será el primer conjunto excepto ese elemento.
Si decidimos invertir la
operación (diferencia entre segundo conjunto y el primero), vemos que el
resultado cambia.
1 |
var consultaDiferencia2 =
consulta2.Except(consulta1); |
Lo cual generará el
siguiente resultado:
En este caso,
comprobamos que el resultado comprende el Segundo conjunto, al que se le ha
eliminado el elemento común (Pedido número 2).