Linq - конвертировать ILookup в другой ILookup - PullRequest
1 голос
/ 07 ноября 2010

Это должно быть просто, но я не могу придумать хороший способ сделать это.Как вы преобразуете ILookup в другой ILookup?Например, как бы вы скопировали / клонировали ILookup, создав другой ILookup с теми же ключами и теми же группами?

Вот моя неудачная попытка:

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

Может кто-нибудь улучшить это?*

- Брайан

Ответы [ 2 ]

4 голосов
/ 07 ноября 2010

Как насчет этого:

return lookup
  .SelectMany (grp => grp, (grp, item) => new { grp.Key, item})
  .ToLookup (x => x.Key, x => x.item);
1 голос
/ 07 ноября 2010

Делает ли это то, что вы хотите?

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

Конечно, если вы хотите как-то преобразовать значения, возможно, вы хотите что-то вроде этого:

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

Обратите внимание, что этот метод содержит промежуточные значения в KeyValuePair, который, будучи типом значения, хранится в стеке и, следовательно, не требует каких-либо промежуточных выделений памяти. Я профилировал тест, который создает Lookup<int,int> с 100 ключами, каждый из которых содержит 10 000 элементов (всего 1 000 000).

  • Создание Lookup делает 1610 выделений.
  • Копирование его с помощью моего метода делает 1712 выделений (все выделения, необходимые для его создания, плюс одно для каждого делегата в вызове SelectMany и одно для перечислителя для каждого ключа).
  • Копирование его с анонимными объектами вместо KeyValuePair дает 1 001 712 выделений (все выделения, необходимые для копирования, плюс одно для каждого элемента).

С точки зрения процессора, даже при 100 000 элементов на ключ производительность Lookup между двумя методами копирования была одинаковой. С 1 000 000 элементов на ключ производительность была разной для двух методов:

  • 5,1 сек для создания
  • 5,9 с для копирования с KeyValuePair
  • 6,3 сек для копирования с анонимными объектами
...