2

这应该很简单,但我想不出一个好的方法来做到这一点。如何将一个 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);
}

任何人都可以改善这一点吗?

——布赖恩

4

2 回答 2

4

这个怎么样:

return lookup
  .SelectMany (grp => grp, (grp, item) => new { grp.Key, item})
  .ToLookup (x => x.Key, x => x.item);
于 2010-11-07T03:33:58.813 回答
2

这是做你想做的吗?

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

请注意,此方法将中间值保存在 aKeyValuePair中,作为值类型,存储在堆栈中,因此不需要任何中间内存分配。我分析了一个测试,该测试使用 100 个键创建一个Lookup<int,int>,每个键有 10,000 个项目(总共 1,000,000 个)。

  • 创建Lookup1610 分配。
  • 用我的方法复制它会进行 1712 次分配(创建它所需的所有分配加上SelectMany调用中的每个委托一个,每个键的枚举数一个)。
  • 使用匿名对象复制它而不是进行KeyValuePair1,001,712 次分配(复制所需的所有分配加上每个项目一个)。

CPU 方面,即使每个键有 100,000 个元素Lookup,两种复制方法之间的性能也是相同的。每个键有 1,000,000 个元素,两种方法的性能不同:

  • 5.1 秒创建
  • 5.9 秒复制KeyValuePair
  • 使用匿名对象复制 6.3 秒
于 2010-11-07T03:43:32.280 回答