Domanda

Questo dovrebbe essere semplice, ma non riesco a pensare ad un buon modo per farlo. Come si fa a trasformare un iLookup in un altro iLookup? Ad esempio, come è possibile copiare / clonare un iLookup, producendo un'altra iLookup con le stesse chiavi e gli stessi gruppi?

Ecco il mio tentativo zoppo:

static ILookup<TKey, TValue> Copy<TKey, TValue>(ILookup<TKey, TValue> lookup)
{
    return lookup
        .ToDictionary(
            grouping => grouping.Key,
            grouping => grouping.ToArray())
        .SelectMany(pair =>
            pair
                .Value
                .Select(value =>
                    new KeyValuePair<TKey, TValue>(pair.Key, value)))
        .ToLookup(pair => pair.Key, pair => pair.Value);
}

Qualcuno può migliorare questa?

- Brian

È stato utile?

Soluzione

Questo fare ciò che si vuole?

static ILookup<TKey, TValue> Copy<TKey, TValue>(ILookup<TKey, TValue> lookup)
{
    return lookup.
           SelectMany(g => g,
                     (g, v) => new KeyValuePair<TKey, TValue>(g.Key, v)).
           ToLookup(kvp => kvp.Key, kvp => kvp.Value);
}

Naturalmente, se si vuole trasformare i valori in qualche modo, forse si desidera qualcosa di simile:

static ILookup<TKey, TValueOut> Transform<TKey, TValue, TValueOut>(
       ILookup<TKey, TValue> lookup,
       Func<TValue, TValueOut> selector)
{
    return lookup.
           SelectMany(g => g,
                      (g, v) => new KeyValuePair<TKey, TValueOut>(g.Key, selector(v))).
           ToLookup(kvp => kvp.Key, kvp => kvp.Value);
}

Si noti che questo metodo contiene i valori intermedi in un KeyValuePair che, essendo un tipo di valore, memorizzato nello stack e pertanto non richiede alcuna allocazioni di memoria intermedie. Ho fatto il profilo di un test che crea un Lookup<int,int> con 100 tasti, ciascuno con 10.000 voci (per un totale di 1.000.000).

  • Creazione del Lookup fa 1610 allocazioni.
  • Copia con il mio metodo non 1712 allocazioni (tutti gli stanziamenti necessari per creare lo più uno per ciascun delegato nella chiamata SelectMany e uno per l'enumeratore per ogni tasto).
  • Copia con anonimi oggetti invece di KeyValuePair fa 1,001,712 allocazioni (tutti gli stanziamenti necessari per copiare più uno per ogni elemento).

CPU-saggio, anche con 100.000 elementi per chiave per le prestazioni Lookup tra i due metodi di copiatura era identica. Con 1.000.000 di elementi per tasto, la prestazione è stata diversa tra i due metodi:

  • 5.1 sec per creare
  • 5.9 sec a copiare con KeyValuePair
  • 6.3 sec per copiare con anonimi oggetti

Altri suggerimenti

Che ne dite di questo:

return lookup
  .SelectMany (grp => grp, (grp, item) => new { grp.Key, item})
  .ToLookup (x => x.Key, x => x.item);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top