Linq:创建空 IGrouping

bri*_*rns 5 linq igrouping ilookup

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

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
}
Run Code Online (Sandbox Code Playgroud)

问题是,即使传入序列不包含具有该键的值,生成的 IDictionary 也应该有一个 default(TKey) 条目。这可以以纯函数的方式完成吗?(不使用可变数据结构。)

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

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

ilm*_*tte 5

接受的答案是我一直在寻找的,但它对我不起作用。也许我错过了一些东西,但它没有编译。我必须修改代码才能修复它。这是对我有用的代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用

var emptyGroup = new EmptyGroup<Customer, AccountingPaymentClient>();
Run Code Online (Sandbox Code Playgroud)


Amy*_*y B 4

您无法从 GroupBy 或 ToLookup 获取空组。也许有一个故意的原因。

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

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

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;
Run Code Online (Sandbox Code Playgroud)

现在,如果您想要一个空组,只需为其添加一个类:

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>();
  }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用:

EmptyGroup<TKey, TValue> empty = new EmptyGroup<TKey, TValue>(Key = default<TKey>());
Run Code Online (Sandbox Code Playgroud)