如何在列表中进行迭代,以便最后一个迭代步骤返回到第一个对象

本文关键字:迭代 最后一个 返回 一个对象 列表 | 更新日期: 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是我提供的压缩函数。

这种方法所需的代码要少得多,而且不太可能导致索引错误。