C# C数据表分组后如何对解决方案进行排序?

C# C数据表分组后如何对解决方案进行排序?,c#,linq,datatable,sql-order-by,C#,Linq,Datatable,Sql Order By,我有一张桌子。我把那张桌子的行分组。列是可选的。 表中的列:天、时间、国家、城市、降雨量。 我想将解决方案复制到新表中 代码: 分组后,它显示下了多少雨 q[0]: { AllKeys { "Tuesday, "06:00", "Austria" }, AllField { "1" } } q[1]: { AllKeys { "Monday", "12:00", "Slovakia" }, AllField { "3" } } q[2]: { AllKeys { "Tuesday, "06:00

我有一张桌子。我把那张桌子的行分组。列是可选的。 表中的列:天、时间、国家、城市、降雨量。 我想将解决方案复制到新表中

代码:

分组后,它显示下了多少雨

q[0]: { AllKeys { "Tuesday, "06:00", "Austria" }, AllField { "1" } }
q[1]: { AllKeys { "Monday", "12:00", "Slovakia" }, AllField { "3" } }
q[2]: { AllKeys { "Tuesday, "06:00", "Slovakia" }, AllField { "1,5" } }
q[3]: { AllKeys { "Monday", "11:00", "Slovakia" }, AllField { "4" } }
我想按键的升序排序:

q[0] tartalma { AllKeys { "Monday", "11:00", "Slovakia" }, AllField { "4" } }
q[1] tartalma { AllKeys { "Monday", "12:00", "Slovakia" }, AllField { "3" } }
q[2] tartalma { AllKeys { "Tuesday, "06:00", "Austria" }, AllField { "1,5" } }
q[3] tartalma { AllKeys { "Tuesday, "06:00", "Slovakia" }, AllField { "1" } }
如果用户希望按日期和时间更改排序,则必须按日期和时间对列进行排序。 这是行不通的,因为我不知道会有多少把钥匙:

var q2 = q.OrderBy(x => x.AllKeys.First()))
.ThenBy(x => x.AllKeys.ToList()[1]);

您能帮助我,如何对查询进行排序吗?

就像您可以为GroupBy提供自定义的iQualityComparer一样,您也可以为OrderBy提供自定义的IComparer。基本上,AllKeys属于IEnumerable类型,因此您需要一个IComparer来获取这些元素并将每个元素与默认的比较器进行比较,但您必须使用反射来获得这些元素:

public class EnumerableComparer : IComparer<IEnumerable<object>> {
    public int Compare(IEnumerable<object> xs, IEnumerable<object> ys) {
        var xe = xs.GetEnumerator();
        var ye = ys.GetEnumerator();

        var sofar = 0;
        while (sofar == 0 && xe.MoveNext()) {
            if (!ye.MoveNext())
                sofar = 1;
            else {
                var ct = typeof(Comparer<>).MakeGenericType(xe.Current.GetType());
                var c = ct.GetProperty("Default").GetValue(null);
                var fc = ct.GetMethod("Compare");
                sofar = (int)fc.Invoke(c, new[] { xe.Current, ye.Current });
            }
        }
        if (sofar == 0 && ye.MoveNext())
            sofar = -1;

        return sofar;
    }
}

如果要将结果转换为DataTable,则需要使用反射,但在决定如何处理结果列中的AllKey时会遇到问题。

您可以在按此方式进行选择时对它们进行分组后进行排序{AllKeys=group.Key.OrderByt=>t,…GroupBy是否为您工作?您是否使用一个特殊的比较器来比较IEnumerable?在GroupBy和Select之间,您可以将OrderByg=>g.Key,比较器与适当的比较器放在一起。您需要一个扩展方法来将结果复制到一个新的数据表中。您希望Al中有什么类型lKeys专栏?这能回答你的问题吗?{AllKeys=group.Key.OrderByt=>t,…这只是对查询行中的键进行排序。非常感谢!我是根据用户选择的列和操作列表创建表的,而不是从查询中创建表的。此查询的foreach将填充数据表。如果您能给我发送学习这些技术的资源,我将非常高兴。@Lother我不再是了我知道我的所有来源,但我想说,大量堆栈溢出搜索可以帮助您将各个部分组合起来,而LINQPad中的大量实验可以帮助您理解转储方法,尤其是对象结构。这个答案的唯一问题是,它将在内存中而不是在DB中完成,但取决于可能使用的键数甚至更好。@EugenePodskal是否有办法处理不在内存中的DataTable?请注意,原始问题在baseTable之后有一个可计算的字段,并且正在对DataTable使用字段选择语法。
public class EnumerableComparer : IComparer<IEnumerable<object>> {
    public int Compare(IEnumerable<object> xs, IEnumerable<object> ys) {
        var xe = xs.GetEnumerator();
        var ye = ys.GetEnumerator();

        var sofar = 0;
        while (sofar == 0 && xe.MoveNext()) {
            if (!ye.MoveNext())
                sofar = 1;
            else {
                var ct = typeof(Comparer<>).MakeGenericType(xe.Current.GetType());
                var c = ct.GetProperty("Default").GetValue(null);
                var fc = ct.GetMethod("Compare");
                sofar = (int)fc.Invoke(c, new[] { xe.Current, ye.Current });
            }
        }
        if (sofar == 0 && ye.MoveNext())
            sofar = -1;

        return sofar;
    }
}
var q = baseTable.AsEnumerable()
                 .GroupBy(row => columnsToGroupBy.Select(c => row[c]), comparer) //eg: day, time, country
                 .Select(group => new {
                     AllKeys = group.Key,
                     AllField = group.Sum(row => double.Parse(row["rain"].ToString()))
                 })
                 .OrderBy(r => r.AllKeys, new EnumerableComparer());