Pergunta

Estou tendo problemas para articular as diferenças entre ILookup<TKey, TVal> e IGrouping<TKey, TVal>, e estou curioso se eu entender corretamente agora. Linq agravou a questão produzindo sequências de IGrouping itens e também me dando um ToLookup Método de extensão. Então, parecia que eles eram iguais até eu parecer mais de perto.

var q1 = 
    from n in N
    group n by n.MyKey into g
    select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>

Que é equivalente a:

var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>

O que se parece muito com:

var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>

Estou correto nas seguintes analogias?

  1. Um IGrouping<TKey, TVal> é um único grupo (ou seja, uma sequência com chave), análoga a KeyValuePair<TKey, TVal> onde o valor é realmente uma sequência de elementos (em vez de um único elemento)
  2. Um IEnumerable<IGrouping<TKey, TVal>> é uma sequência daqueles (semelhante ao que você recebe quando itera sobre um IDictionary<TKey, TVal>
  3. Um ILookup<TKey, TVal> é mais como um IDictionary<TKey, TVal> onde o valor é realmente uma sequência de elementos
Foi útil?

Solução

Sim, tudo isso está correto.

E ILookup<TKey, TValue> também se estende IEnumerable<IGrouping<TKey, TValue>> Assim, você pode iterar em todos os pares de chave/coleção, bem como (ou em vez de) apenas procurar as teclas específicas.

Eu basicamente penso em ILookup<TKey,TValue> como sendo como IDictionary<TKey, IEnumerable<TValue>>.

Ter em mente que ToLookup é uma operação "faça agora" (execução imediata), enquanto um GroupBy é adiado. Por acaso, com a maneira como "Pull Linq" funciona, quando você começa a puxar IGroupings do resultado de um GroupBy, ele precisa ler todos os dados de qualquer maneira (porque você não pode mudar o grupo no meio do caminho), enquanto em outras implementações poderá produzir um resultado de streaming. (Isso faz em Push Linq; eu esperaria que o LINQ fosse o mesmo.)

Outras dicas

Há outra diferença importante entre Ilookup e Idictionary: o primeiro aplica imutabilidade no sentido de que aqui não há métodos para alterar os dados (exceto quando o consumidor executa um elenco explícito). Por outro lado, o Idictionary possui métodos como "Adicionar" que permitem alterar os dados. Portanto, da perspectiva da programação funcional e/ou da programação paralela, o iLookup é melhor. (Eu gostaria que houvesse também uma versão do Ilookup que atribua apenas um valor a uma chave em vez de um grupo.)

(BTW., Parece valer a pena apontar que a relação entre ienumerable e ilist é um pouco semelhante à de Ilookup e Idictionary - o primeiro é imutável, o último não é.)

GroupBy e ToLookUp tem quase a mesma funcionalidade EXCETO isto: Referência

Grupo: O operador do Grupoby retorna grupos de elementos com base em algum valor -chave. Cada grupo é representado por objeto igrupo.

TOLOOKUP: Tolookup é o mesmo que Groupby; A única diferença é que a execução do grupo é adiada, enquanto a execução de Tolookup é imediata.

Vamos limpar a diferença usando o código de amostra. Suponha que tenhamos uma classe representando Person modelo:

class Personnel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Level { get; set; }
}

Depois disso, definimos uma lista de personnels como abaixo:

 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 }
    };

Agora eu preciso obter o personnels agrupados pelo seu nível. Eu tenho duas abordagens aqui. usando GroupBy ou ToLookUp. Se eu usar GroupBy, como afirmado anteriormente, ele usará a execução diferida, isso significa que, quando você itera através da coleção, o próximo item pode ou não ser calculado até que seja necessário.

 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);
    }

No código acima, agrupei primeiro o personnels, mas antes de itera, eu removi alguns personnels. Como GroupBy usa a execução diferida, portanto o resultado final não incluirá os itens removidos, porque o agrupamento será computado no foreach aponte aqui.

Resultado:

2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

Mas se eu reescrever o código acima como abaixo: (observe que o código é o mesmo que o código anterior, exceto GroupBy é substituído 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 usa execução imediata, significa que quando eu chamo o ToLookUp Método, o resultado é gerado e o grupo é aplicado; portanto, se eu remover algum item de personnels Antes da iteração, isso não afetará o resultado final.

Resultado:

1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

Observação: GroupBy e ToLookUp Ambos retornam tipos diferentes também.

Você pode usar o ToDictionary em vez de Tolookup, mas precisa prestar atenção a isso :(referência)

O uso de tolookup () é muito semelhante ao do Todictionary (), ambos permitem especificar seletores de chave, seletores de valor e comparadores. A principal diferença é que o tolookup () permite (e espera) as teclas duplicadas, enquanto o Todictionary () não

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top