我想知道如何在Haskell中交换列表中的每个第二个元素。
示例输出应如下所示:
swap [1,2,3,4,5]
[2,1,4,3,5]
到目前为止我所拥有的是
swap :: [a] -> [a]
swap [] = []
swap (x:xs) = head xs : [x]
但是这只交换前两个元素,并且当我尝试加载包含该函数的文件时,我使该函数递归的任何尝试都会导致错误。如何使其递归?
答案 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)
但请注意,head
和tail
的使用是不必要的,模式匹配可以使这里的事情更加清晰。
答案 3 :(得分:2)
import Data.Function(on)
swap = map snd . concatMap reverse . groupBy ((==) `on` fst) . zip (cycle "aabb")
不要认真对待我的解决方案,我只是想改善我的Haskell-Foo ......