简体   繁体   English

Linq-将ILookup转换为另一个ILookup

[英]Linq - convert an ILookup into another ILookup

This should be simple, but I can't think of a good way to do it. 这应该很简单,但是我想不出一个好方法。 How do you transform an ILookup into another ILookup? 如何将一个ILookup转换为另一个ILookup? For example, how would you copy/clone an ILookup, producing another ILookup with the same keys and same groups? 例如,您将如何复制/克隆一个ILookup,以产生另一个具有相同键和相同组的ILookup?

Here's my lame attempt: 这是我la脚的尝试:

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

Can anyone improve this? 有人可以改善吗?

-- Brian -布赖恩

How about this: 这个怎么样:

return lookup
  .SelectMany (grp => grp, (grp, item) => new { grp.Key, item})
  .ToLookup (x => x.Key, x => x.item);

Does this do what you want? 这是您想要的吗?

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

Of course, if you want to transform the values somehow, maybe you want something like this: 当然,如果您想以某种方式转换值,也许您想要这样的事情:

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

Note that this method holds intermediate values in a KeyValuePair which, being a value type, is stored on the stack and thus doesn't require any intermediate memory allocations. 请注意,此方法将中间值保存在KeyValuePair中,该值是一种值类型,存储在堆栈中,因此不需要任何中间内存分配。 I profiled a test that creates a Lookup<int,int> with 100 keys, each having 10,000 items (for a total of 1,000,000). 我分析了一个测试,该测试创建了一个具有100个键的Lookup<int,int> ,每个键具有10,000个项(总计1,000,000个)。

  • Creating the Lookup does 1610 allocations. 创建Lookup会进行1610个分配。
  • Copying it with my method does 1712 allocations (all the allocations required to create it plus one for each delegate in the SelectMany call and one for the enumerator for each key). 用我的方法复制它会执行1712个分配(创建它所需的所有分配,再加上SelectMany调用中的每个委托一个,每个键中的枚举器一个)。
  • Copying it with anonymous objects instead of KeyValuePair does 1,001,712 allocations (all the allocations required to copy plus one for each item). 使用匿名对象而不是KeyValuePair复制它会进行1,001,712分配(复制所需的所有分配,每一项加一个)。

CPU-wise, even with 100,000 elements per key in the Lookup performance between the two copying methods was identical. 在CPU方面,即使两种复制方法之间的Lookup性能相同,每个键甚至有100,000个元素。 With 1,000,000 elements per key, the performance was different between the two methods: 每个键具有1,000,000个元素,两种方法的性能有所不同:

  • 5.1 sec to create 5.1秒建立
  • 5.9 sec to copy with KeyValuePair KeyValuePair复制5.9秒
  • 6.3 sec to copy with anonymous objects 用匿名对象复制需要6.3秒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM