Domanda

Ho avuto difficoltà a articolare le differenze tra ILookup<TKey, TVal> e IGrouping<TKey, TVal> , e sono curioso di sapere se ho capito bene ora. LINQ aggravato il problema con la produzione di sequenze di elementi IGrouping mentre mi dà anche un metodo di estensione ToLookup. Così sembrava fossero la stessa fino a quando ho guardato più da vicino.

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

che è equivalente a:

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

Il che assomiglia molto:

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

Sono corretto nei seguenti analogie?

  1. Un IGrouping<TKey, TVal> è un singolo gruppo (cioè una sequenza a chiave), analogo al KeyValuePair<TKey, TVal> cui il valore è in realtà una sequenza di elementi (anziché un singolo elemento)
  2. Un IEnumerable<IGrouping<TKey, TVal>> è una sequenza di coloro (simile a quello che si ottiene quando l'iterazione di un IDictionary<TKey, TVal>
  3. Un ILookup<TKey, TVal> è più come un IDictionary<TKey, TVal> se il valore è in realtà una sequenza di elementi
È stato utile?

Soluzione

Sì, tutti questi sono corretti.

E ILookup<TKey, TValue> estende anche IEnumerable<IGrouping<TKey, TValue>> in modo da poter iterare su tutte le coppie chiave / raccolta, nonché (o al posto di) solo guardando le chiavi particolari.

Io fondamentalmente penso ILookup<TKey,TValue> come essendo come IDictionary<TKey, IEnumerable<TValue>>.

Tenete a mente che ToLookup è un "farlo ora" operazione (esecuzione immediata), mentre un GroupBy è differita. Come spesso accade, con il modo in cui "tirare LINQ" funziona, quando si inizia a tirare IGroupings dal risultato di un GroupBy, deve leggere tutti i dati in ogni caso (perché non è possibile passare a metà gruppo attraverso), mentre in altre implementazioni esso può essere in grado di produrre un risultato streaming. (Non Push LINQ;. Mi aspetterei LINQ to Events per essere lo stesso)

Altri suggerimenti

C'è un'altra differenza importante tra iLookup e IDictionary: il primo fa rispettare immutabilità nel senso che qui esistono metodi per modificare i dati (tranne quando il consumatore effettua un cast esplicito). Al contrario, IDictionary ha metodi come "Aggiungi", che consentono di modificare i dati. Così, dal punto di vista funzionale programmazione e / o programmazione parallela, iLookup è migliore. (Solo Vorrei che ci fosse anche una versione di iLookup che assegna un solo valore a una chiave piuttosto che un gruppo.)

(. A proposito, sembra pena sottolineare che il rapporto tra IEnumerable e IList è in qualche modo simile a quello tra iLookup e IDictionary -. Il primo è immutabile, quest'ultimo non è)

GroupBy e ToLookUp ha quasi stessa funzionalità TRANNE in questo modo: Riferimento

  

GroupBy: L'operatore GroupBy ritorna gruppi di elementi basati su alcuni   valore della chiave. Ogni gruppo è rappresentato da IGrouping   oggetto.

     

ToLookup: ToLookup è lo stesso di GroupBy; l'unica differenza   è l'esecuzione di GroupBy è differito che è esecuzione ToLookup   immediato.

Consente chiara la differenza utilizzando il codice di esempio. supponiamo di avere una classe che rappresenta il modello Person:

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

dopo che noi definiamo una lista di personnels come di seguito:

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

Ora ho bisogno di ottenere il personnels raggruppati per loro livello. Ho due approccio qui. utilizzando GroupBy o ToLookUp. Se io uso GroupBy, come detto prima, userà esecuzione differita, questo significa, che quando si scorrere l'insieme l'elemento successivo può o non può essere calcolato fino a quando non è richiesto.

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

Nel codice sopra, innanzitutto raggruppato il personnels, ma prima iterazione, ho rimosso alcuni personnels. Come GroupBy usa esecuzione differita, in modo che il risultato finale non comprenderà elementi rimossi, perché raggruppamento sarà calcolando nel punto foreach qui.

Output:

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

Ma se riscrivo il codice di cui sopra, come di seguito: (si noti che il codice è uguale al codice precedente, ad eccezione GroupBy è sostituito dal 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);
    }

Come ToLookUp usa esecuzione immediata, ciò significa che quando chiamo il metodo ToLookUp, risultato viene generato e applicato gruppo, quindi se rimuovere qualsiasi elemento da personnels prima iterazione, che effetto solito il risultato finale.

Output:

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 e ToLookUp sia restituire tipi diversi troppo

Si potrebbe utilizzare ToDictionary invece di ToLookup, ma è necessario prestare attenzione a questo: ( riferimento )

  

L'utilizzo di ToLookup () è molto simile a quella di ToDictionary (),   entrambi consentono di specificare selettori a chiave, selettori di valore, e   comparatori. La differenza principale è che ToLookup () permette (e   si aspetta) le chiavi duplicate mentre ToDictionary () non lo fa

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top