2011-02-04 73 views
4

我正在研究一個Polygon類,它在Array[Vec2]中保存了一個頂點數組(Vec2是一個簡單的case類,定義了x和y )。現在尋找一個scala-esque方法迭代通過訪問「next」元素的列表

,我想實現的功能在Array[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數組中的下一個項目

我已閱讀IterableLike中定義的sliding方法,但似乎是非旋轉的,即它不會考慮第一個項目在最後一個項目之後,因此不會返回它。

那麼對此有什麼好的「scala-esque」方法呢?

+0

你能澄清一兩件事:你有一組點定義的多邊形,所有的謊言在一些平面,它們都隱含一致繞組(即列表連接[ A,B,C]頂點實際上有一個三角形,(BA)和(CA)(歸一化)的叉積產生垂直於平面的單位矢量。這是正確的嗎? – 2011-02-04 08:28:39

+0

是的,這是正確的。注意我在二維空間中工作,所以我們甚至不必去談它的正常情況(當然,除非這有助於找到解決方案)。 – pdinklag 2011-02-04 08:42:29

回答

10

當然你也可以使用sliding

(vertices :+ vertices.head) sliding 2 
0

可能的解決方案可能不是嘗試訪問下一個元素,而是保留前一個元素。所以,你可以採取foldLeft您的需求 - 讓邊緣數組的一個切片,而不第一要素,把第一個元素作爲起始值和未來是這樣的:

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)

+0

這將允許我將每個頂點連接到下一個頂點,但連接(5,0)將不足。 – pdinklag 2011-02-04 09:13:14

1

有可能(a)枚舉所有(有向)邊(由索引定義到它們的頂點),(b)給定邊的列表和頂點列表,構造一個線段數組(通過查找)。我認爲,這兩項任務都可以在沒有突變的情況下完成。

的第一個任務(和一個你似乎與掙扎)最多(在Haskell)如下處理:

foldr (\x a -> (x,(x+1) `mod` 4):a) [] [0..3] 

而剩下的就是概括這個例子。

這是你想要做的嗎?

編輯:添加了一個例子

+0

不確定是否誠實,我將Haskell源代碼翻譯成Scala有點麻煩......我是函數式編程的新手,不知道Haskell的語法 - 但是如果能爲我分解它,我仍然會很感激? – pdinklag 2011-02-04 09:15:03

+0

當然(我不認識斯卡拉,所以請原諒我)。 foldr是一個右聯合摺疊列表。我們傳給它的函數被賦予一個索引x,併產生邊(x,(x + 1)%4),其中%是模運算的縮寫(加法「繞回」4)。然後它把這個邊緣包含在結果列表中。因此,給定一個從0到3的頂點索引列表,我們計算相應的邊緣。 – 2011-02-04 09:26:41

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)) 
0

如果要避免複製整個列表中Debilski的解決方案,你可以做稍微詳細:

vertices.view.sliding(2).map(p => if (p.size == 1) p :+ vertices.head else p) 

這產生了一個視圖序列上的迭代器的視圖s o不要感到驚訝。

1

帶zip的另一種方法。這次使用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))