2013-05-26 15 views
6

我想將[1,2,3,4]轉換成[[1 2] [2 3] [3 4]][(1 2) (2 3) (3 4)]。在clojure我有(partition 2 1 [1,2,3,4])。我如何在Haskell中做到這一點?我懷疑在標準API中有這樣的功能,但我找不到它。成對列表中的元素

+3

爲什麼Clojure的電話本'partition'?如果你劃分了一些東西,那麼你分裂的方式就是這些部分的總和。 – AndrewC

+0

哦 - 找到[clojure docs](http://clojuredocs.org/clojure_core/clojure.core/partition)描述「分區n步驟coll:返回列表中有n個項目的惰性序列,每個項目在偏移步驟 之外。如果沒有提供步驟,默認爲n,即分區 不重疊。「 – AndrewC

回答

19

標準的把戲這是zip列表與它自己的tail

> let xs = [1,2,3,4] in zip xs (tail xs) 
[(1,2),(2,3),(3,4)] 

爲了說明爲什麼這工作,在視覺上排隊列表,它的尾巴。

 xs = 1 : 2 : 3 : 4 : [] 
tail xs = 2 : 3 : 4 : [] 

並注意zip正在從每列中製作一個元組。

有兩個更微妙的原因,這總是做正確的事:當任一列表用完元素

  • zip停止。這是有道理的,因爲我們不能在最後有一個「不完整的對」,它也確保我們不會從單個元素列表中獲得對。
  • xs爲空時,可能會預期tail xs發生異常。但是,因爲zip 首先檢查其第一個參數,當它看到它是空列表時,第二個參數 永遠不會被評估。

以上所有內容對於zipWith都適用,因此,無論何時需要將函數成對應用於相鄰元素,您都可以使用相同的方法。

對於像Clojure的partition這樣的通用解決方案,標準庫中沒有任何內容。但是,你可以嘗試這樣的事:

partition' :: Int -> Int -> [a] -> [[a]] 
partition' size offset 
    | size <= 0 = error "partition': size must be positive" 
    | offset <= 0 = error "partition': offset must be positive" 
    | otherwise = loop 
    where 
    loop :: [a] -> [[a]] 
    loop xs = case splitAt size xs of 
       -- If the second part is empty, we're at the end. But we might 
       -- have gotten less than we asked for, hence the check. 
       (ys, []) -> if length ys == size then [ys] else [] 
       (ys, _) -> ys : loop (drop offset xs) 
+0

所以在標準庫中沒有通用函數嗎?例如,如果想要沒有元組但不是三元組,或者如果我想重複或跳過一些值,就像http://clojuredocs.org/clojure_core/clojure.core/partition – piotrek

+0

@piotrek:標準庫中沒有,不,但是,它並不難實現,我已經給我的答案添加了一個示例實現 – hammar

1

只是拋出另一個答案有使用了不同的方法:

對於n = 2你想簡單zip列表與它的尾巴。對於n = 3,您想要用尾巴和尾巴的尾巴來壓縮列表。這種格局進一步延續,所以我們要做的是概括它:

partition n = sequence . take n . iterate tail 

但是,這只是一個作品抵消1.概括,我們只需要看看genrated列表中的偏移。它永遠有以下形式:

[[1..something],[2..something+1],..] 

因此,所有剩下要做的就是選擇每offset個元素,我們應該罰款。我shamelessy偷@ertes這個版本從this question

everyNth :: Int -> [a] -> [a] 
everyNth n = map head . takeWhile (not . null) . iterate (drop n) 

整個函數現在變爲:

partition size offset = everyNth offset . sequence . take size . iterate tail 
+0

不幸的是,你的概括給出了某種奇怪的排列 – flq