首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linq:创建空IGrouping

Linq:创建空IGrouping
EN

Stack Overflow用户
提问于 2011-11-08 13:43:37
回答 3查看 2.9K关注 0票数 4

我想使用Linq创建一个函数来总结传入的值序列。该函数应如下所示:

代码语言:javascript
复制
IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values)
{
    return values
        .ToLookup(val => GetKey(val))         // group values by key
        .Union(*an empty grouping*)           // make sure there is a default group
        .ToDictionary(
            group => group.Key,
            group => CreateSummary(group));   // summarize each group
}

需要注意的是,即使传入的序列不包含具有该键的值,结果IDictionary也应该有一个默认值(TKey)条目。这可以通过纯函数的方式来完成吗?(不使用可变数据结构。)

我能想到的唯一方法就是在查找时调用.Union,然后将其输入到字典中。但这将要求我创建一个空的IGrouping,如果没有显式的类,这似乎是不可能的。有没有一种优雅的方法来做到这一点呢?

编辑:我们可以假设TKey是一个值类型。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-11-09 00:07:19

你不能从GroupBy获取空组,也不能从ToLookup获取。也许这是故意的原因。

这可以用纯函数的方式来完成吗?(不使用可变数据结构。)

虽然这样的学术要求可能很有趣,但任何解决方案都应该与简单直接的实现进行比较。

代码语言:javascript
复制
Dictionary<TKey, Summary<TKey>> result = values
  .GroupBy(val => GetKey(val))
  .ToDictionary(g => g.Key, g => CreateSummary(g));

TKey x = default(TKey);
if (!result.ContainsKey(x))
{
  result[x] = CreateSummary(Enumerable.Empty<TValue>());
}

return result;

现在,如果你想要一个空的Group,只需要为它添加一个类:

代码语言:javascript
复制
public class EmptyGroup<TKey, TValue> : IGrouping<TKey, TValue>
{
  public TKey Key {get;set;}

  public IEnumerator GetEnumerator()
  {
    return GetEnumerator<TValue>();
  }
  public IEnumerator<TValue> GetEnumerator<TValue>()
  {
    return Enumerable.Empty<TValue>().GetEnumerator<TValue>();
  }
}

如下所示:

代码语言:javascript
复制
EmptyGroup<TKey, TValue> empty = new EmptyGroup<TKey, TValue>(Key = default<TKey>());
票数 4
EN

Stack Overflow用户

发布于 2014-01-16 01:33:47

公认的答案就是我想要的,但它对我不起作用。也许我遗漏了什么,但它不能编译。我不得不修改代码来修复它。以下是为我工作的代码:

代码语言:javascript
复制
public class EmptyGroup<TKey, TValue> : IGrouping<TKey, TValue>
{
    public TKey Key { get; set; }

    public IEnumerator<TValue> GetEnumerator()
    {
        return Enumerable.Empty<TValue>().GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

像这样使用

代码语言:javascript
复制
var emptyGroup = new EmptyGroup<Customer, AccountingPaymentClient>();
票数 4
EN

Stack Overflow用户

发布于 2011-11-08 14:18:12

您可以添加第二个select,在该select中检查查找表是否有条目,如果没有,则创建一个新的查找表。这与您提议的联合解决方案的不同之处在于,如果存在其他值,则不会添加默认值。

请参见:

代码语言:javascript
复制
IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values) 
{ 
    return values 
        .ToLookup(val => GetKey(val))         // group values by key 
        .Select(x => x.Any() ? x : Enumerable.Repeat(default(TKey), 1).ToLookup(x => GetKey(x)))
        .ToDictionary( 
            group => group.Key, 
            group => CreateSummary(group));   // summarize each group 
} 

如果您需要具有联合的解决方案,则可以使用相同的逻辑来创建默认查找表,如下所示:

代码语言:javascript
复制
IDictionary<TKey, Summary<TKey>> Summarize<TKey, TValue>(IEnumerable<TValue> values) 
{ 
    return values 
        .ToLookup(val => GetKey(val))         // group values by key 
        .Union(Enumerable.Repeat(default(TKey), 1).ToLookup(x => GetKey(x)))
        .ToDictionary( 
            group => group.Key, 
            group => CreateSummary(group));   // summarize each group 
} 

希望这能有所帮助

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8046425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档