我想基于2个条件对pointcloud进行分组
简单的Y所以我写了pointcloudH.GroupBy(KVP => KVP.Value.Y)
其中KVP是KeyValuePair<string,System.Drawing.Point>
现在我想通过X对其进行分组X == (previousX + 1)
据我所知,我应该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 ???
答案 0 :(得分:2)
我不认为LINQ是这类工作的最佳工具,但它可以实现。重要的是要考虑Point.X
组与Point
组中相对Point.Y
的索引之间的关系。一旦您意识到要按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
排序。)在第一个ThenBy(p => p.X)
子句后添加OrderBy
。
答案 1 :(得分:0)
通过执行2个单独的group by子句无法解决您的问题。我创建了一个应该适用于您的问题的小样本。这些是代码中发生的关键事项:
创建一个变量,只要“链”被破坏,该变量就会递增。这是每当下一个值不等于前一个+ 1时。这样我们就可以按每个'链'的唯一键进行分组。
课程计划 { public struct Point { public static Point Create(int x,int y) { 返回new Point(){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();
}
}