我正在处理一个Polygon类,它在Array[Vec2]
中保存一个顶点数组(Vec2
是一个定义x和y的简单大小写类。)
现在,我想实现一个函数来返回Array[LineSegment]
中多边形的边缘(其中LineSegment也是一个定义开始和结束的简单案例类)。
解决方案是创建将每个顶点连接到数组中的下一个顶点的线段,最后将最后一个顶点连接到第一个顶点。
我只习惯于命令式编程,所以这是我的必要方法:
def edges: Array[LineSegment] = {
val result = new Array[LineSegment](vertices.length)
for (i <- 0 to vertices.length - 2) {
result.update(i, LineSegment(vertices.apply(i), vertices.apply(i + 1)))
}
result.update(edges.length - 1, LineSegment(vertices.head, vertices.last))
result
}
这很好用,但很简单。我想在这里使用函数式编程的优点,但我有点坚持。
我的想法是把它写成类似的东西:
def edges: Array[LineSegment] = {
for (v <- vertices) yield
LineSegment(v, if (v == vertices.last) vertices.head else /* next? */)
}
问题是,在给定当前项v
的情况下,无法访问数组中的 next 项。
我已经阅读了sliding
中定义的IterableLike
方法,但这似乎是非旋转的,即它不会考虑最后一项之后的第一项,因此不会把它归还。
那么什么是一个好的“scala-esque”方法呢?
答案 0 :(得分:10)
当然,您可以使用sliding
:
(vertices :+ vertices.head) sliding 2
答案 1 :(得分:4)
def cyclicSliding[A](s:Seq[A]) = s.zip(s.tail :+ s.head)
println(cyclicSliding(List(1,2,3,4)))
//--> List((1,2), (2,3), (3,4), (4,1))
答案 2 :(得分:1)
有可能(a)枚举所有(有向)边(由其顶点的索引定义),(b)给定边列表和顶点列表,以构造线段数组(通过执行查找) )。我认为,这两项任务都可以在没有变异的情况下完成。
第一个任务(以及你似乎正在努力解决的任务)可以按如下方式处理(在Haskell中):
foldr (\x a -> (x,(x+1) `mod` 4):a) [] [0..3]
剩下的就是概括这个例子。
这是你想要做的吗?
编辑:添加了一个例子
答案 3 :(得分:1)
拉链的另一种方式。这次使用zipAll:
val l1 = List(1,2,3,4)
l1 zipAll (l1.tail,null,l1.head)
res: List((1,2), (2,3), (3,4), (4,1))
答案 4 :(得分:0)
可能的解决方案可能不是尝试访问下一个元素,而是保持流行的元素。因此,您可以根据需要采用foldLeft
- 获取一个没有第一个元素的edge数组,将第一个元素作为起始值,接下来是这样的:
val n = 5
(0 to n).toList.slice(1, n + 1).foldLeft(0)((x, y) => {print(x,y); y})
输出:(0,1)(1,2)(2,3)(3,4)(4,5)
答案 5 :(得分:0)
如果你想避免像在Debilski的解决方案中那样复制整个列表,你可以稍微详细一点:
vertices.view.sliding(2).map(p => if (p.size == 1) p :+ vertices.head else p)
这会在一系列视图上产生一个迭代器视图,所以不要感到惊讶。