将聚合写为Sql语法

时间:2018-12-01 02:38:09

标签: c# linq

我真的很想了解聚合的工作原理,并且有一个解决方案可以将IEnumerable映射到较新的C#7元组。

我想,如果将其编写为Linq Sql语法,我可以理解得更多。

有人愿意刺它吗?


IEnumerable<(string Key, string Value)> many = DataToPivot();

(string XXXX, string YYYY, string ZZZZ) agg = 
many.Aggregate((XXXX: default(string),
                YYYY: default(string),
                ZZZZ: default(string)),
                  (a, i) =>
                  {
                      switch (i.Key)
                      {
                          case "xxxx":
                              return (i.Value, a.YYYY, a.ZZZZ);
                          case "yyyy":
                              return (a.XXXX, i.Value, a.ZZZZ);
                          case "zzzz":
                              return (a.XXXX, a.YYYY, i.Value);
                          default:
                              return a;
                      }
                  });

1 个答案:

答案 0 :(得分:2)

据我所知Aggregate没有查询语法(有关更多信息,请参见documentation)。该文档还应该能够解释该功能的工作原理。

您正在使用的重载获取聚合的初始值(第一个参数),并将累加函数(第二个参数)应用于每个元素,并返回中间的聚合值。因此,您的示例从输入数据中生成了3个字符串,基本上返回了每个键的最后一个字符串值(如果输入数据不包含该键的任何项目,则返回default(string)

如果这是您的要求,则您(也不应该)不需要使用Aggregate函数,因为您没有进行聚合。您可以通过以下示例获得相同的结果(假设所有键都出现在many输入中):

IEnumerable<(string Key, string Value)> many = DataToPivot();

var d = many.GroupBy(i => i.Key)
            .ToDictionary(g => g.Key, g => g.Last().Value);

(string XXXX, string YYYY, string ZZZZ) agg = (d["xxxx"], d["yyyy"], d["zzzz"]);

如果不需要元组,下面的方法也可以处理数据集中根本不存在键的情况(如果键不存在,则返回默认值):

d.TryGetValue("xxxx", out string x);
d.TryGetValue("yyyy", out string y);
d.TryGetValue("zzzz", out string z);

Aggregate例如进行字符串连接-但您可以改用String.Join()

many.GroupBy(i => i.Key)
    .ToDictionary(g => g.Key, g => string.Join(",", g));

如果您仍然想使用Aggrergate,可以这样重写它:

many.GroupBy(i => i.Key)
    .ToDictionary(g => g.Key, g => g.Aggregate((a, i) => i));

这基本上是Last()使用Aggregate()实现的;并使用TryGetValue可以满足您的需求。

更一般的一点:使用这种方法,您可以容纳多个键值,而无需专门对其进行编码。在这种情况下,您甚至可能不需要ToDictionary调用,例如像这样:

many.GroupBy(i => i.Key)
    .Select(g => new { g.Key, Result = g.Aggregate((a, i) => i) })
    .ToList();