如何在列表中进行迭代,以便最后一个迭代步骤返回到第一个对象
本文关键字:迭代 最后一个 返回 一个对象 列表 | 更新日期: 2023-09-27 18:01:15
我有一个组成平面的点列表。我想在连续点之间创建边,并将它们添加到另一个列表中。
这是我目前拥有的代码:
// Get points forming the plate
ArrayList points = part.points;
// Number of points forming the plate
int pointCount = points.Count;
// Create edges
List<LineSegment> edges = new List<LineSegment>();
for (int i = 0; i < pointCount - 1; i++)
{
// Get start and end points
Point start = points[i];
Point end = points[i+1];
// Create edge
LineSegment edge = new LineSegment(start, end);
// Add edge to the list
edges.Add(edge);
}
它不太起作用,因为它没有在列表上的最后一个点和第一个点之间创建最后一条边。纠正它的方法是什么?我可以用这样一个if语句来实现它:
for (int i = 0; i < pointCount; i++)
{
// Get start and end points
Point start = points[i] as Point;
Point end;
if (i == pointCount-1) end = points[0] as Point;
else end = points[i+1] as Point;
// Rest of the code here
}
但我相信还有一种更优雅的方法可以做到这一点。在Python中,我会从-1开始循环,这样第一条边实际上就是将最后一点连接到第一点,但这在C#中是不可能的。
编辑:API将点列表作为ArrayList给出。
"优雅"解决方案使用模数:
for (int i = 0; i < pointCount; i++)
{
…
// for i+1 == pointCount this will yield points[0]
Point end = points[(i+1) % pointCount] as Point;
…
}
但是,我相信您使用的if
语句可读性更强。
注意:也要使用List<T>
而不是ArrayList
。
使用模运算符(在C#中为´%´(。
for (int i = 0; i < pointCount; i++)
{
// Get start and end points
Point start = points[i] as Point;
Point end = points[(i + 1) % pointCount];
// Rest of the code here
}
我会杀死所有的索引和显式循环,并描述问题本身,而不是如何解决它。
var offsetPoints = points.Skip(1).Concat(new[]{points.First()});
List<LineSegment> edges =
points.Zip(offsetPoints, (p1, p2) => new LineSegment(p1, p2)).ToList();
我只是创建了一个偏移列表,它在开始时跳过第一个元素,并在结束时添加它,这样偏移列表和原始列表的长度相同。
为了说明,我将从一些序列开始:
{p1,p2,p3,p4,p5}
并产生一个序列:
{p2、p3、p4、p5、p1}
然后,我将它们压缩在一起,从每个序列中出现在相同位置的点创建线段。
继续上面的例子,使用任意函数从两者中的元素创建一个新的序列:
{f(p1,p2(,f(p2,p3(,f
其中f
是我提供的压缩函数。
这种方法所需的代码要少得多,而且不太可能导致索引错误。