【问题标题】:How to group in Linq based on previous Value如何根据先前的值在 Linq 中进行分组
【发布时间】:2017-04-22 23:51:32
【问题描述】:

我想根据 2 个条件对点云进行分组

  1. 在 Y 上很简单,所以我写了 pointcloudH.GroupBy(KVP => KVP.Value.Y),其中 KVP 是 KeyValuePair<string,System.Drawing.Point>

  2. 如果X == (previousX + 1),现在我也想按 X 分组它 据我所知,我应该ThenBy(),但我必须在括号之间写什么?

这里有一个例子可以更好地说明我想要实现的目标

示例点云

(x|y) (1|1),(2|1),(4|1),(1|2),(2|3),(3|3),(4|3),(5|8),(9|10)

第 1 步之后。看起来像这样

group1 (1|1),(2|1),(4|1)
group2 (1|2)
group3 (2|3),(3|3),(4|3)
group4 (5|8)
group5 (9|10)

第 2 步之后。应该是这样的

group1 (1|1),(2|1)
group2 (4|1)
group3 (1|2)
group4 (2|3),(3|3),(4|3)
group5 (5|8)
group6 (9|10)

当前代码

var Hgroup = pointcloudH.OrderBy(KVP => KVP.Value.Y) // order by Y
                        .GroupBy(KVP => KVP.Value.Y) // groub by Y
                        .ThenBy(KVP => KVP.Value.X); // group by X ???

【问题讨论】:

  • 我想你会想要GroupBy而不是OrderBy,但这有点棘手......
  • @JonSkeet 哦,这只是一个复制粘贴错字:) 我会解决这个问题,但我仍然遇到同样的问题
  • @JonSkeet 所以它是固定的,我还添加了我当前的代码被剪断

标签: c# linq linq-group


【解决方案1】:

我不认为 LINQ 是此类工作的最佳工具,但可以实现。重要的部分是考虑您的Point.XPoint.Y 组中相对Point 的索引之间的关系。一旦你意识到你想按Point.X - Index 对它们进行分组,你可以这样做:

var Hgroup = pointcloudH.OrderBy(p => p.Y)
                        .GroupBy(p => p.Y)
                        .SelectMany(yGrp =>
                                    yGrp.Select((p, i) => new {RelativeIndex = p.X - i, Point = p})
                                        .GroupBy(ip => ip.RelativeIndex, ip => ip.Point)
                                        .Select(ipGrp => ipGrp.ToList()))
                        .ToList();

请注意,这可能会比常规迭代算法执行得最差。我的 pointcloudH 是一个数组,但您可以更改 lambda 以反映您自己的列表。此外,如果您想推迟执行,请删除 ToList()。这是为了简化调试器中的结果检查。

如果您想对Point.Y 组中的所有点进行分组,而不考虑它们的索引(即也按Point.X 排序。在第一个OrderBy 子句之后添加ThenBy(p => p.X)

【讨论】:

    【解决方案2】:

    您的问题无法通过执行 2 个单独的 group by 子句来解决。我创建了一个小样本,应该可以解决您的问题。这些是代码中发生的关键事情:

    • 构造“镜像”数组并在索引 0 处插入第一项的副本,用于跟踪前一点
    • 创建一个在“链”中断时递增的变量。这是每当下一个值不等于前一个 + 1 时。这样我们可以按每个“链”的唯一键进行分组。

      类程序 { 公共结构点 { 公共静态点创建(int x,int y) { 返回新点() { X = x, Y = y }; }

          public int X { get; set; }
          public int Y { get; set; }
      
          public override string ToString()
          {
              return string.Format("({0}|{1})", X, Y);
          }
      }
      
      static void Main(string[] args)
      {
          //helper to avoid to much keystrokes :)
          var f = new Func<int, int, Point>(Point.Create);
          //compose the point array
          //(1|1),(2|1),(4|1),(1|2),(2|3),(3|3),(4|3),(5|8),(9|10)
          var points = new[] { f(1, 1), f(2, 1), f(4, 1), f(1, 2), f(2, 3), f(3, 3), f(4, 3), f(5, 8), f(9, 10) }.OrderBy(p => p.Y).ThenBy(p => p.X);;
      
          //create a 'previous point' array which is a copy of the source array with a item inserted at index 0
          var firstPoint = points.FirstOrDefault();
          var prevPoints = new[] { f(firstPoint.X - 1, firstPoint.Y) }.Union(points);
      
          //keep track of a counter which will be the second group by key. The counter is raised whenever the previous X was not equal
          //to the current - 1
          int counter = 0;
      
          //the actual group by query
          var query = from point in points.Select((x, ix) => new { current = x, prev = prevPoints.ElementAt(ix) })                        
                      group point by new { point.current.Y, prev = (point.prev.X == point.current.X - 1 ? counter : ++counter) };
      
          //method chaining equivalent
          query = points.Select((x, ix) => new { current = x, prev = prevPoints.ElementAt(ix) })
                        .GroupBy(point => new { point.current.Y, prev = (point.prev.X == point.current.X - 1 ? counter : ++counter) });
      
          //print results
          foreach (var item in query)
              Console.WriteLine(string.Join(", ", item.Select(x=> x.current)));            
      
          Console.Read();
      }
      

      }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多