Haskell函数用于交换列表中的每个第二个元素

时间:2011-11-13 19:28:45

标签: list haskell recursion

我想知道如何在Haskell中交换列表中的每个第二个元素。

示例输出应如下所示:

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

到目前为止我所拥有的是

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

但是这只交换前两个元素,并且当我尝试加载包含该函数的文件时,我使该函数递归的任何尝试都会导致错误。如何使其递归?

4 个答案:

答案 0 :(得分:12)

您需要一次抓取2个元素:

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

允许奇数长度列表需要最后一行 - 它匹配长度恰好为1的列表,因此它不会与其他两种情况(长度为0,长度为2或更长)重叠。

答案 1 :(得分: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]

答案 2 :(得分:2)

@ j_random_hacker的解决方案更好,但是,如果你想看到你的实现完成,你可以试试这个:

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

但请注意,headtail的使用是不必要的,模式匹配可以使这里的事情更加清晰。

答案 3 :(得分:2)

import Data.Function(on)

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

不要认真对待我的解决方案,我只是想改善我的Haskell-Foo ......