当前位置: 首页 > 知识库问答 >
问题:

如何在C#中用LINQ动态分组和计算聚合和/最大值数据

巫马承德
2023-03-14

我们有一个API来处理来自不同来源的数据(数据库、webservices、纯文本、...)所以我们将它存储在列表结构中。我们有这段代码来选择它们中的一些列,并应用函数来获取新数据(如和两列,...)

Func<dynamic[], object>[] leftFunctions = new Func<dynamic[], object>[this.Columns.Count];
IEnumerable<dynamic[]> returnValue = null
j = 0;
foreach (JoinDataColumn dataColum in this.Columns.OrderBy(x => x.Index))
{
     //Obtenemos para cada columna la funcion
     leftFunctions[j++] = dataColum.getLeftFunction(LeftDataQuery);
}
returnValue = (await LeftDataQuery.ExecuteAsync(parameters))
    .Select(x => leftFunctions.Select(f => f.Invoke(x)).ToArray());

在上面的代码中:LeftDataquery是一个获取列表的类,其中的数据执行此操作,并返回list

await LeftDataQuery.ExecuteAsync(parameters)

LeftFuncions是从源数据创建新数据的公式,“lefdataquery[1]+lefdataquery[2]”或简单地“lefdataquery[0]”以获得第一列的数据。

在JoinDataColumn类中,我对结果列表的每一列都有一个描述:name、type和agregate函数。

最后,用户可以选择要分组的列和其他列的Aggregation公式(sum,max,min,count distinct,...)。现在,我有了带有原始源的列子集的returnvalue和要分组的列的索引列表,以及带有它们的Aggreation公式的索引列表(例如,索引1是一个和,等等)

public enum DataColumnAggregation { NONE = 0, SUM = 1, MAX = 2, MIN = 3 }

任何关于如何按这些数据分组并得到和/最大/最小值的想法…

做了一些测试,我编写了这段代码,但问题是Groupby不能使用对象数组作为参数。有没有想过让GroupBy用这个方法工作?“

    public enum DataColumnAggregation { NONE = 0, SUM = 1, MAX = 2, MIN = 3 }

    static void Main(string[] args)
    {
        List<object[]> returnValue = new List<object[]> { new object[] { "C1", 1, 2 }, new object[] { "C2", 3, 4 }, new object[] { "C1", 1, 3 } };


        DataColumnAggregation[] config = new DataColumnAggregation[] { DataColumnAggregation.NONE, DataColumnAggregation.SUM, DataColumnAggregation.MAX };
        //TODO agregar por la columna 0 , sumar la columna 1 y maximo de la columna 2 de returnvalue

        var resultado2 = returnValue.GroupBy(x => getGroupByColumns(x,config)).Select(x=>agregar(x, config));

    }

    private static object[] agregar(IGrouping<string[], object[]> x, DataColumnAggregation[] config)
    {
        List<object> result = new List<object>();
        for (int i = 0; i < config.Length; i++)
        {
            if (config[i] == DataColumnAggregation.NONE)
            {
                result.Add(x.Select(xy => xy[i]).FirstOrDefault());
            }
            if (config[i] == DataColumnAggregation.SUM)
            {
                result.Add(x.Sum(xy => Convert.ToInt32(xy[i]))); 
            }
            if (config[i] == DataColumnAggregation.MAX)
            {
                result.Add(x.Max(xy => xy[i])); 
            }
            if (config[i] == DataColumnAggregation.MIN)
            {
                result.Add(x.Min(xy => xy[i])); 
            }
        }
        return result.ToArray();
    }


    private static string[] getGroupByColumns(object[] x, DataColumnAggregation[] config)
    {
        List<string> group = new List<string>();
        for (int i = 0; i< config.Length; i++)
        {
            if (config[i] == DataColumnAggregation.NONE) group.Add(x[i].ToString());
        }
        return group.ToArray();
    }

谢谢

共有1个答案

丁理
2023-03-14

由于您正在尝试按String[](或更好的List )分组,因此需要将IEqualityComparer传递给比较元素的GroupBy

public class IEnumerableSequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> {
    public bool Equals(IEnumerable<T> x, IEnumerable<T> y) =>
        Object.ReferenceEquals(x, y) || (x != null && y != null && (x.SequenceEqual(y)));

    public int GetHashCode(IEnumerable<T> src) {
        // Will not throw an OverflowException
        //unchecked {
        //    return src.Where(e => e != null).Select(e => e.GetHashCode()).Aggregate(17, (a, b) => 23 * a + b);
        //}
        var hc = new HashCode();
        foreach (var v in src)
            hc.Add(v);
        return hc.ToHashCode();
    }
}

名为make的工厂类帮助创建比较器:

public static class Make {
    public static IEqualityComparer<IEnumerable<T>> SequenceEqualityComparer<T>() => new IEnumerableSequenceEqualityComparer<T>();
    public static IEqualityComparer<IEnumerable<T>> SequenceEqualityComparer<T>(T _) => new IEnumerableSequenceEqualityComparer<T>();
}

现在可以使用序列相等比较器调用groupby:

var resultado2 = returnValue.GroupBy(x => getGroupByColumns(x,config), Make.SequenceEqualityComparer<string>()).Select(x=>agregar(x, config));

注意:这导致组IEnumerable 。如果您更喜欢ilist ,只需在相等比较器类和因子类中用ilist替换IEnumerable。或者添加具有适当名称更改的其他ilist版本。

 类似资料:
  • 我有发票,每张发票都包含一个项目列表。每个项目都有(除其他外)以下字段: 姓名 数量 总计 每张发票都有(除其他外)字段: _id 创建 项目 发票存在于专门的Mongo集合中,称为发票。 我想获取包含指定项目的所有发票,其中每个发票都需要返回以下信息: _id 让我们称之为元组 如果发票列出给定项目两次,则相应的发票将生成两个投影实例。如果发票根本没有列出给定的项目,则结果中不存在此发票。 无论

  • 我正在查找与url匹配但返回自定义对象的记录。 我有这个模型。。 我想查询该模型并匹配url,但返回如下响应: 我需要能够通过将记录的ip与过程中的变量进行比较,动态计算反应的ip是否为真。 一次尝试是 但我似乎无法集中IP并查看我的变量IP是否在该数组中。 谢谢你的帮助。我第一次问!

  • 问题内容: 假设我有一个表,在字符串()列中包含格式化的值。这些值应该是由某些const符号分隔的字符串(让它是分号)。例如, 或者 分隔符始终是分隔符,不能是值的一部分。 我需要检查该表中是否已经有一行,并且该列中的值列表至少包含指定的一项。换句话说,我有一个值列表: 分隔符: 我需要编写一个执行此操作的linq-to-sql查询: 应该提到的是,任何搜索值都可以包含其他值。也就是说,我可能正在

  • 我有一些文件存储在Elasticsearch中,如下所示: 我想得到的是字段1、字段2或字段3对每个文档的最大次数的计数,按日期分组,即。期望结果如下: 我在date上使用了一个术语聚合,但不知道如何比较不同的字段,以便使用Elasticsearch聚合来执行此max and count类型的操作。有什么建议吗?

  • 问题内容: 我正在尝试转换此查询(已经可以使用) 对于Linq to SQL,但我不知道自己在做什么错。看我的尝试 我只需要对建筑物进行分组并计算每个建筑物有多少用户。 问题答案: 只需使用以下方法:

  • 本文向大家介绍在C ++中使用分而治之算法的最大子数组总和,包括了在C ++中使用分而治之算法的最大子数组总和的使用技巧和注意事项,需要的朋友参考一下 假设我们有一个带有正值和负值的数据列表。我们必须找到其总和最大的连续子数组的总和。假设列表包含{-2,-5,6,-2,-3,1,5,-6},则最大子数组的总和为7。它是{6,-2,-3的总和,1,5} 我们将使用分而治之方法解决此问题。步骤如下所示