2011-11-13 193 views
2

我想知道如何交換Haskell中列表的每個第二個元素。Haskell函數交換列表中的每個第二個元素

示例輸出應該是這樣的:

swap [1,2,3,4,5] 
[2,1,4,3,5] 

我至今是

swap :: [a] -> [a] 
swap [] = [] 
swap (x:xs) = head xs : [x] 

但這只是交換前兩個元素的任何企圖我使使函數的遞歸原因當我嘗試加載包含該函數的文件時發生錯誤。如何使其遞歸?

+0

如何顯示您的嘗試和它導致的錯誤? – delnan

+0

我試圖做的是交換(x:xs)= head xs:[x] swap xs。嘗試加載文件時的錯誤是「haskell.hs:3:25: 函數'[x]'被應用於兩個參數, ,但其類型'[a]'沒有 在'( :)',即'[x] swap xs' 在表達式中:head xs:[x] swap xs 在'swap'等式中:swap(x:xs)= head xs:[x] swap xs 失敗,模塊加載:無。「 – sineil

回答

12

你需要在一個時間搶出2個元素:

swap [] = [] 
swap (x:y:rest) = y:x:(swap rest) 
swap [x] = [x] 

需要的最後一行允許奇數長度列表 - 它具有長度正好1列表匹配,所以它不重疊另外兩種情況中的任何一種(長度爲0,長度爲2或更多)。

+4

在「(x:y:rest)」情況下,空元素和單元素模式可以更簡潔地表示爲'swap other = other'。 – Chuck

+0

感謝您的幫助。我已經想通過添加swap [x] = [x] – sineil

+1

@Chuck:True來讓您的代碼適用於奇數大小的列表,但是您必須將該案例放在最後,因爲它與另一個案例重疊。當案件不相交時,我感覺更舒服,因爲那時他們可以以任何順序(可能這是不好的風格?) –

2

@ j_random_hacker的解決方案是更好的,但是,如果你想看到你的執行完成,你可以試試這個:

swap [] = [] 
swap (x:[]) = [x] 
swap (x:xs) = head xs : x : (swap $ tail xs) 

通知然而,使用headtail是不必要的,和模式匹配能讓事情變得更清潔。

2
import Data.Function(on) 

swap = map snd . concatMap reverse . groupBy ((==) `on` fst) . zip (cycle "aabb") 

不要把我的解決方案太嚴重了,我只是想提高我的哈斯克爾 - 美孚...

5

除了其他相當出色的答覆,這裏是使用了一些解決方案非常方便的圖書館。首先,安裝split,它提供了許多非常好的分割列表的方法。我們針對這個問題的策略是首先將你的列表分割成大小爲2的塊,然後交換每個塊,然後將結果連接成平面列表。這裏的關鍵功能是如何工作的:

Prelude Data.List.Split> chunk 2 [1..11] 
[[1,2],[3,4],[5,6],[7,8],[9,10],[11]] 

要交換的每個塊的元素,我們可以簡單地調用reverse。所以最終的結果是:

Prelude Data.List.Split> let swap = concat . map reverse . chunk 2 
Prelude Data.List.Split> swap [1..5] 
[2,1,4,3,5] 
相關問題