/ / Agregar filas de un IEnumerable a otro según las condiciones: c #, linq, c # -4.0

Agregar filas de un IEnumerable a otro según las condiciones: c #, linq, c # -4.0

Tengo dos matrices ..

var data1 = new[] {
new { Product = "Product 1", Year = 2009, Sales = 1212 },
new { Product = "Product 2", Year = 2009, Sales = 522 },
new { Product = "Product 1", Year = 2010, Sales = 1337 },
new { Product = "Product 2", Year = 2011, Sales = 711 },
new { Product = "Product 2", Year = 2012, Sales = 2245 },
new { Product = "Product 3", Year = 2012, Sales = 1000 }
};

var data2 = new[] {
new { Product = "Product 1", Year = 2009, Sales = 1212 },
new { Product = "Product 1", Year = 2010, Sales = 1337 },
new { Product = "Product 2", Year = 2011, Sales = 711 },
new { Product = "Product 2", Year = 2012, Sales = 2245 }
};

Lo que quiero hacer es comprobar cada uno de los Product y Year en data2, y si existe alguna fila para cualquier combinación de tales Product y Year en data1 pero no en data2 luego agrega esa fila a data2.

Ejemplo.. En data2, los distintos productos son Product1 y Product2 y distintos años son Year1, Year2, Year3 y Year4.

En data1 existe una fila { Product = "Product 2", Year = 2009, Sales = 522 }, que no está presente en data2, así que deseo agregarlo a data2.

Lo que puedo hacer es obtener productos y años distintos en dos variables.

Luego haga una para cada bucle en ambos y verifique si la combinación existe en data1 pero no en data2 y, si es así, agréguela a data2.

Lo que me gustaría obtener es una única consulta LINQ que pueda hacer este trabajo por mí en lugar de hacer dos distintas por separado y luego hacer un par para cada bucle.

Gracias

Respuestas

2 para la respuesta № 1

Puede hacer que esto funcione en una sola consulta. Sin embargo, será subóptimo, porque para cada elemento en data1 Debería verificar tres condiciones, que potencialmente requieren pasar por todo el data2 para una complejidad temporal de O (m * n) (aunque la complejidad espacial sigue siendo O (1)).

Sin embargo, puede evitar un bucle idéntico:

var uniqueProd = new HashSet<string>(data2.Select(d=>d.Product));
var uniqueYear = new HashSet<int>(data2.Select(d=>d.Year));
var knownPairs = new HashSet<Tuple<string,int>>(
data2.Select(d=>Tuple.Create(d.Product, d.Year))
);
var newData2 = data2.Concat(
data1.Where(d =>
uniqueProd.Contains(d.Product)                       // The product is there
&&  uniqueYear.Contains(d.Year)                          // The year is there
&& !knownPairs.Contains(Tuple.Create(d.Product, d.Year)) // Combination is not there
)
).ToArray();

Esta solución es O (m + n) en el tiempo y también O (n) en el espacio.


1 para la respuesta № 2

No haré ningún reclamo de eficiencia, pero es posible en una sola consulta.

Si está satisfecho con dejar que Union se encargue de eliminar duplicados, puede hacer lo siguiente:

var newd2 = data2.Union(
from d1 in data1
where
(from d2p in data2 from d2y in data2
select new { d2p.Product, d2y.Year })
.Distinct().Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
select d1);

Alternativamente, puede excluir coincidencias de datos2 preexistentes y usar Concat

var newd2 = data2.Concat(
from d1 in data1
where
(from d2p in data2 from d2y in data2 select new { d2p.Product, d2y.Year })
.Distinct().Any(mp => mp.Product == d1.Product && mp.Year == d1.Year) &&
!data2.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
select d1
);

OTOH, no pude resistir algunos tiempos.Si llamamos al uso de Union como 1, el uso de Concat varía del 73% del tiempo, la creación de HashSets usa el 827% del tiempo y extraer el par único establecido toma el 54%, y omitir el .Distinct () toma el 27%, aunque el El conjunto de datos es demasiado lento para diferenciar algunos de estos.

Sacando los pares y volcando Distinct:

var newdd = (from d2p in data2 from d2y in data2 select new { d2p.Product, d2y.Year });
var newd2 = data2.Concat(
from d1 in data1
where
newdd.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year) &&
!data2.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
select d1
);