【问题标题】:Linq group by, order by valuesLinq 分组依据,按值排序
【发布时间】:2016-11-11 18:43:33
【问题描述】:

我需要帮助 我有表:

   Id          Day                 Group       Value 
 -------------------------------------------------
   1           2016-10-11          1           10.5
   2           2016-10-11          1           10.8
   3           2016-10-11          1           10.7
   4           2016-10-11          1           10.6
   5           2016-10-11          1           10.5
   6           2016-10-11          1           10.4
   7           2016-10-11          1           10.8
   8           2016-10-11          1           10.2
   9           2016-10-11          1           10.0
   10          2016-10-11          1           10.9
   11          2016-10-11          2           10.1
   12          2016-10-11          2           10.0
   13          2016-10-11          2           10.1
   14          2016-10-11          2           10.6
   15          2016-10-11          2           10.7
   16          2016-10-11          2           10.2
   17          2016-10-11          2           10.0
   18          2016-10-11          2           10.5
   19          2016-10-11          2           10.5
   20          2016-10-11          2           10.8
   21          2016-10-12          1           11.1
   22          2016-10-12          1           11.7
   23          2016-10-12          1           11.0
   24          2016-10-12          1           11.4
   25          2016-10-12          1           11.7
   26          2016-10-12          1           11.8
   27          2016-10-12          1           11.1
   28          2016-10-12          1           11.1
   29          2016-10-12          1           11.4
   30          2016-10-12          1           11.6
   31          2016-10-12          2           11.9 
   32          2016-10-12          2           11.6
   ...

我想要

  • 按价值排序
  • 按组分组
  • 按天分组
  • 并且只获得如下值:

[[[10.5,10.8],[10.0,10.1]],[[11.1,11.7],[11.6,11.9]]](示例)

分别我需要更多地使用这个值,当我得到像例子一样的值时,我在 Day 中得到更多的值。然后我将此批次拆分为 4 批次,然后从每个组中选择第一个值。因此,每个组我将有 4 个值,并且在 1 天我将有 2 个批次,每个批次将有 4 个值。因为我需要在每批中都有 5 个值,比如最后一个值,所以我找到 Max Value 并将其添加到具有 4 个值的批中。不知道你看懂了没有我的代码:

    var valueList = await Task.Factory.StartNew(() =>

    (
        from pv in db.Values
        where DbFunctions.TruncateTime(pv.Day) >= startDate      
        && DbFunctions.TruncateTime(pv.Day) <= endDate           
        orderby pv.Value
        //group pv by pv.Day into gpv
        select pv
    ));

var group1 = await Task.Factory.StartNew(() => (
(
    from vl in valueList
    where vl.Group == 1
    select vl) 
));

var group2 = await Task.Factory.StartNew(() =>
(
    from vl in valueList
    where vl.Group == 2
    select vl
));

var group3 = await Task.Factory.StartNew(() =>
(
    from vl in valueList
    where vl.Group == 3
    select vl 
));


var group1Split = group1.Split(group1.Count() / 4 + 1).Select(x => x.First());
var group1Max = group1.Max();
var group2Split = group2.Split(group2.Count() / 4 + 1).Select(x => x.First());
var group2Max = group2.Max();
var group3Split = group3.Split(group3.Count() / 4 + 1).Select(x => x.First());
var group3Max = group3.Max();

var group1Values = group1Split.Concat(group1Max);
var group2Values = group2Split.Concat(group2Max);
var group3Values = group3Split.Concat(group3Max);

var groupAllValues = group1Values.Concat(group2Values).Concat(group3Values);
var groupSplitAllValues = groupAllValues.Split(5);

return Request.CreateResponse(HttpStatusCode.OK, groupSplitAllValues.ToList());

更新:

这项工作:

var result = db.Values
    .Where(x => (DbFunctions.TruncateTime(x.Day)) >= startDate
    && (DbFunctions.TruncateTime(x.Day)) <= endDate)
   .GroupBy(x => new { Day = x.Day, Group = x.Group })
   .Select(x => x.Select(y => y.Value).OrderBy(z => z).ToList()).ToList();

我明白了:

[
[10.0, 10.2, 10.4, 10.5, 10.5, 10.6, 10.7, 10.8, 10.8, 10.9],
[10.0, 10.0, 10.1, 10.1, 10.2, 10.5, 10.5, 10.6, 10.7, 10.8],
[11.0, 11.1, 11.1, 11.1, 11.4, 11.4, 11.6, 11.7, 11.7, 11.8],
[...]
]

但在这种情况下,我需要将每个批次拆分为 2 部分,并从该部分中选择第一个值。所以我将有 2 个值,然后我希望从这批中连接到 2 个值最大值,所以对于这个例子,我的最终结果将是:

[
[10.0, 10.6, 10.9],
[10.0, 10.2, 10.8],
[11.0, 11.4, 11.8],
[...]
]

对于拆分我使用这种方法:

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int length)
        {
            if (length <= 0)
                throw new ArgumentOutOfRangeException("length");

            var section = new List<T>(length);

            foreach (var item in source)
            {
                section.Add(item);

                if (section.Count == length)
                {
                    yield return section.AsReadOnly();
                    section = new List<T>(length);
                }
            }

            if (section.Count > 0)
                yield return section.AsReadOnly();
        }

【问题讨论】:

  • 所以你想连接一些会被 group by 语句丢失的值。这是一个关于通过 linq 连接这些值的问题:[链接] (stackoverflow.com/questions/18203169/…)。因此,您可以根据需要多次使用 group ,然后将值连接起来。之后,您可以订购结果数据。

标签: c# linq linq-to-sql


【解决方案1】:

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace ConsoleApplication23
{
    class Program
    {
        static void Main(string[] args)
        {

            DataTable dt = new DataTable();
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Day", typeof(DateTime));
            dt.Columns.Add("Group", typeof(int));
            dt.Columns.Add("Value", typeof(decimal));

            dt.Rows.Add(new object[] {1 , DateTime.Parse("2016-10-11"), 1, 10.5});
            dt.Rows.Add(new object[] {2 , DateTime.Parse("2016-10-11"), 1, 10.8});
            dt.Rows.Add(new object[] {3 , DateTime.Parse("2016-10-11"), 1, 10.7});
            dt.Rows.Add(new object[] {4 , DateTime.Parse("2016-10-11"), 1, 10.6});
            dt.Rows.Add(new object[] {5 , DateTime.Parse("2016-10-11"), 1, 10.5});
            dt.Rows.Add(new object[] {6 , DateTime.Parse("2016-10-11"), 1, 10.4});
            dt.Rows.Add(new object[] {7 , DateTime.Parse("2016-10-11"), 1, 10.8});
            dt.Rows.Add(new object[] {8 , DateTime.Parse("2016-10-11"), 1, 10.2});
            dt.Rows.Add(new object[] {9 , DateTime.Parse("2016-10-11"), 1, 10.0});
            dt.Rows.Add(new object[] {10, DateTime.Parse("2016-10-11"), 1, 10.9});
            dt.Rows.Add(new object[] {11, DateTime.Parse("2016-10-11"), 2, 10.1});
            dt.Rows.Add(new object[] {12, DateTime.Parse("2016-10-11"), 2, 10.0});
            dt.Rows.Add(new object[] {13, DateTime.Parse("2016-10-11"), 2, 10.1});
            dt.Rows.Add(new object[] {14, DateTime.Parse("2016-10-11"), 2, 10.6});
            dt.Rows.Add(new object[] {15, DateTime.Parse("2016-10-11"), 2, 10.7});
            dt.Rows.Add(new object[] {16, DateTime.Parse("2016-10-11"), 2, 10.2});
            dt.Rows.Add(new object[] {17, DateTime.Parse("2016-10-11"), 2, 10.0});
            dt.Rows.Add(new object[] {18, DateTime.Parse("2016-10-11"), 2, 10.5});
            dt.Rows.Add(new object[] {19, DateTime.Parse("2016-10-11"), 2, 10.5});
            dt.Rows.Add(new object[] {20, DateTime.Parse("2016-10-11"), 2, 10.8});
            dt.Rows.Add(new object[] {21, DateTime.Parse("2016-10-12"), 1, 11.1});
            dt.Rows.Add(new object[] {22, DateTime.Parse("2016-10-12"), 1, 11.7});
            dt.Rows.Add(new object[] {23, DateTime.Parse("2016-10-12"), 1, 11.0});
            dt.Rows.Add(new object[] {24, DateTime.Parse("2016-10-12"), 1, 11.4});
            dt.Rows.Add(new object[] {25, DateTime.Parse("2016-10-12"), 1, 11.7});
            dt.Rows.Add(new object[] {26, DateTime.Parse("2016-10-12"), 1, 11.8});
            dt.Rows.Add(new object[] {27, DateTime.Parse("2016-10-12"), 1, 11.1});
            dt.Rows.Add(new object[] {28, DateTime.Parse("2016-10-12"), 1, 11.1});
            dt.Rows.Add(new object[] {29, DateTime.Parse("2016-10-12"), 1, 11.4});
            dt.Rows.Add(new object[] {30, DateTime.Parse("2016-10-12"), 1, 11.6});
            dt.Rows.Add(new object[] {31, DateTime.Parse("2016-10-12"), 2, 11.9});
            dt.Rows.Add(new object[] {32, DateTime.Parse("2016-10-12"), 2, 11.6});

            var results = dt.AsEnumerable()
                .GroupBy(x => new { day = x.Field<DateTime>("Day"), group = x.Field<int>("Group")})
                .Select(x => x.Select(y => y.Field<decimal>("Value")).OrderBy(z => z).ToList()).ToList();

            List<List<decimal>> groups = new List<List<decimal>>();
            const int NUM_GROUPS = 2;
            foreach (var result in results)
            {
                int size = result.Count;
                int groupSize = (int)(size / NUM_GROUPS); //round down

                List<decimal> newGroup = new List<decimal>() { result[0] };
                groups.Add(newGroup);
                for (int groupNum = 0; groupNum < NUM_GROUPS; groupNum++)
                {
                    newGroup.Add( result.Skip(groupNum * groupSize).Take(groupSize).Max());
                }
            }


        }
    }
}

【讨论】:

  • 好吧,我得到这样的结果:[ [1, 2, 3,....] [1, 2, 3,....] [1, 2, 3,. ...] [1, 2, 3,....] [1, 2, 3,....] ] 但是如何拆分这些批次为每个批次选择第一个值并找到最大值并添加此最大值价值观。示例 [ [4, 6, 8, 9, 10] [2, 4, 5, 8, 8] [1, 1, 6, 9, 10] [1, 2, 4, 4, 7] [3, 3 , 7, 8, 10] ] 对于拆分,我使用有效的方法。
  • 请解释清楚
  • 您如何在我的代码中看到我得到的每个组,我将其拆分为 4 部分,并在每个部分中只选择第一个值,这样我就有 4 个值。然后我将每组的最大值连接到 4 个值,所以最后我为每组有 5 个值。在这种情况下,我应该每天为每个组设置 5 个值。
  • 你能用实际数字举一个更好的例子吗?您的示例令人困惑。
  • 我认为在这种情况下使用传统编码比使用Linq更好。我修改了我的代码,但它与您的预期结果不完全匹配。我稍微编辑一下你应该会得到想要的结果。
【解决方案2】:

这是我如何做的一个示例,我确信一定有一种更优雅的方式来生成输出字符串

static void Main(string[] args)
    {
        List<Example> samples = new List<Example>();
        samples.Add(new Example(1, DateTime.Parse("2016-10-11"), 1, 10.5));
        samples.Add(new Example(2, DateTime.Parse("2016-10-11"), 1, 10.8));
        samples.Add(new Example(3, DateTime.Parse("2016-10-11"), 2, 10.1));
        samples.Add(new Example(4, DateTime.Parse("2016-10-11"), 2, 10.0));
        samples.Add(new Example(5, DateTime.Parse("2016-10-12"), 1, 11.1));
        samples.Add(new Example(6, DateTime.Parse("2016-10-12"), 1, 11.7));
        samples.Add(new Example(7, DateTime.Parse("2016-10-12"), 2, 11.9));
        samples.Add(new Example(8, DateTime.Parse("2016-10-12"), 2, 11.6));

        var daily_results = samples.GroupBy(g => new { g.group, g.date }).GroupBy(g => g.Key.date);

        StringBuilder sb = new StringBuilder();

        sb.Append("[");
        foreach (var group_result in daily_results)
        {
            sb.Append("[");
            foreach(var result in group_result)
            {
                sb.Append($"[{string.Join(",", result.OrderBy(r => r.value).Select(r => r.value))}]");
            }
            sb.Append("]");
        }
        sb.Append("]");

        Console.WriteLine(sb);
        Console.Read();
    }
}
class Example
{
    public int id;
    public DateTime date;
    public int group;
    public double value;
    public Example(int i, DateTime d, int g, double v)
    {
        id = i;
        date = d;
        group = g;
        value = v;
    }
}

更新:输出代码可以这样简化:

        var daily_results = samples.GroupBy(g => new { g.group, g.date }).GroupBy(g => g.Key.date);

        string output = string.Empty;

        daily_results.ToList().ForEach(grp =>
            {
                output += "[";
                grp.ToList().ForEach(res =>
                {
                    output += $"[{string.Join(",", res.OrderBy(r => r.value).Select(r => r.value))}],";
                });
                output = output.TrimEnd(',') + "],";
            });
        Console.WriteLine($"[{output.TrimEnd(',')}]");
        Console.Read();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    相关资源
    最近更新 更多