ILookup<TKey, TVal=""> vsIGrouping<TKey, TVal="">
Pregunta
He estado teniendo problemas para articular las diferencias entre ILookup<TKey, TVal>
y IGrouping<TKey, TVal>
, y estoy curioso por saber si he entendido correctamente ahora.LINQ agravado el problema por la producción de secuencias de IGrouping
los elementos mientras que también me está dando un ToLookup
método de extensión.Así que se sentía como eran la misma hasta que miré más de cerca.
var q1 =
from n in N
group n by n.MyKey into g
select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>
Que es equivalente a:
var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>
Que se parece mucho a:
var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>
Estoy en lo cierto en las siguientes analogías?
- Un
IGrouping<TKey, TVal>
es un único grupo (es decir,una llave de la secuencia), de forma análoga aKeyValuePair<TKey, TVal>
donde el valor es en realidad una secuencia de elementos (en lugar de a un único elemento) - Un
IEnumerable<IGrouping<TKey, TVal>>
es una secuencia de esos (similar a lo que se obtiene cuando se itera sobre unaIDictionary<TKey, TVal>
- Un
ILookup<TKey, TVal>
es más como unIDictionary<TKey, TVal>
donde el valor es en realidad una secuencia de elementos
Solución
Sí, todos esos son correctos.
Y ILookup<TKey, TValue>
también se extiende IEnumerable<IGrouping<TKey, TValue>>
por lo que puede iterar sobre todos los pares de claves / recogida, y también (o en lugar de) simplemente mirando hacia arriba claves particulares.
básicamente pienso en ILookup<TKey,TValue>
como si fuera IDictionary<TKey, IEnumerable<TValue>>
.
Tenga en cuenta que ToLookup
es un "hacerlo ahora" operación (ejecución inmediata), mientras que un GroupBy
es diferido. Si llega el caso, con la forma en que "tirar de LINQ" funciona, cuando se inicia tirando IGrouping
s a partir del resultado de un GroupBy
, tiene que leer todos los datos de todos modos (porque no se puede cambiar a medio camino a través del grupo), mientras que en otras implementaciones puede ser capaz de producir un resultado de streaming. (No en LINQ empuje;. Yo esperaría LINQ a eventos a ser el mismo)
Otros consejos
Hay otra diferencia importante entre iLookup y IDictionary: el primero hace cumplir la inmutabilidad en el sentido que aquí hay métodos para cambiar los datos (excepto cuando el consumidor realiza una conversión explícita). Por el contrario, IDictionary tiene métodos como "Añadir", que permiten cambiar los datos. Así, desde la perspectiva de la programación funcional y / o la programación en paralelo, iLookup es más agradable. (Sólo deseo también hubo una versión de iLookup que asigna un único valor a una tecla en lugar de un grupo.)
(. Por cierto, parece que vale la pena señalar que la relación entre IEnumerable y IList es algo similar a la que existe entre iLookup y IDictionary -. El primero es inmutable, este último no es)
GroupBy
y ToLookUp
tiene casi la misma funcionalidad EXCEPTO este: Referencia
GroupBy:El GroupBy operador devuelve grupos de elementos con base en algunos valor de la clave.Cada grupo está representado por IGrouping objeto.
ToLookup:ToLookup es el mismo que GroupBy;la única diferencia es la ejecución de GroupBy es diferido, mientras que ToLookup de ejecución es inmediata.
Deja clara la diferencia con código de ejemplo.supongamos que tenemos una clase que representa Person
modelo:
class Personnel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Level { get; set; }
}
después de la definición de una lista de personnels
como a continuación:
var personnels = new List<Personnel>
{
new Personnel { Id = 1, FullName = "P1", Level = 1 },
new Personnel { Id = 2, FullName = "P2", Level = 2 },
new Personnel { Id = 3, FullName = "P3", Level = 1 },
new Personnel { Id = 4, FullName = "P4", Level = 1 },
new Personnel { Id = 5, FullName = "P5", Level =2 },
new Personnel { Id = 6, FullName = "P6", Level = 2 },
new Personnel { Id = 7, FullName = "P7", Level = 2 }
};
Ahora necesito conseguir el personnels
agrupados por su nivel.Tengo dos enfoque aquí.el uso de GroupBy
o ToLookUp
.Si yo uso GroupBy
, como se dijo antes, se utilizará la ejecución diferida, esto significa que, cuando se itera a través de la recopilación de la siguiente elemento puede o no puede ser calculada hasta que es llamado para.
var groups = personnels.GroupBy(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
En el código anterior, yo en primer lugar se agrupan las personnels
, pero antes de la iteración, se la he quitado algunos personnels
.Como GroupBy
usa la ejecución diferida, por lo que el resultado final no se incluyen los elementos retirados, porque la agrupación será la computación en la foreach
el punto aquí.
Salida:
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
Pero si me reescribir el código anterior de la siguiente manera:(nota de que el código es el mismo que el código anterior, excepto GroupBy
es reemplazado por ToLookUp
)
var groups = personnels.ToLookup(p => p.Level);
personnels.RemoveAll(p => p.Level == 1);
foreach (var product in groups)
{
Console.WriteLine(product.Key);
foreach (var item in product)
Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
}
Como ToLookUp
utiliza ejecución inmediata, esto significa que cuando yo llame a la ToLookUp
el método, el resultado es generado y de grupo se aplica, así que si puedo eliminar cualquier elemento de personnels
antes de la iteración, que no efecto en el resultado final.
Salida:
1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2
Nota: GroupBy
y ToLookUp
tanto el retorno de los diferentes tipos demasiado.
Usted podría utilizar ToDictionary en lugar de ToLookUp, pero es necesario prestar atención a esto:(referencia)
El uso de ToLookup() es muy similar a la de ToDictionary(), ambos permiten especificar la clave de selectores, el valor de los selectores, y comparers.La principal diferencia es que ToLookup() permite (y espera) el duplicado de las llaves mientras que ToDictionary() no