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?

  1. Un IGrouping<TKey, TVal> es un único grupo (es decir,una llave de la secuencia), de forma análoga a KeyValuePair<TKey, TVal> donde el valor es en realidad una secuencia de elementos (en lugar de a un único elemento)
  2. Un IEnumerable<IGrouping<TKey, TVal>> es una secuencia de esos (similar a lo que se obtiene cuando se itera sobre una IDictionary<TKey, TVal>
  3. Un ILookup<TKey, TVal> es más como un IDictionary<TKey, TVal> donde el valor es en realidad una secuencia de elementos
¿Fue útil?

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 IGroupings 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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top