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

sin*_*eil 2 recursion haskell list

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

示例输出应如下所示:

swap [1,2,3,4,5]  
[2,1,4,3,5]
Run Code Online (Sandbox Code Playgroud)

到目前为止我所拥有的是什么

swap :: [a] -> [a]  
swap [] = []  
swap (x:xs) = head xs : [x]
Run Code Online (Sandbox Code Playgroud)

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

j_r*_*ker 12

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

swap [] = []
swap (x:y:rest) = y:x:(swap rest)
swap [x] = [x]
Run Code Online (Sandbox Code Playgroud)

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

  • 在((x:y:rest)`情况之后,空元素和单元素模式可以更简洁地表达为`swap other = other`. (4认同)
  • @j_random_hacker:不幸的是,我的Arbiter of Style帽子是清洁工,但就个人而言,我非常重视"随机重新排序线并使其工作的能力".在Haskell代码中,在正常情况下获得捕获是非常正常的,因此我认为不会让任何人失望. (4认同)

Dan*_*ner 5

除了其他非常出色的回复之外,这里还有一个使用一些非常方便的库的解决方案.首先,安装split,它提供了许多分割列表的非常好的方法.我们针对这个问题的策略是首先将列表拆分为大小为2的块,然后交换每个块,然后将结果连接回一个平面列表.以下是关键功能的工作原理:

Prelude Data.List.Split> chunk 2 [1..11]
[[1,2],[3,4],[5,6],[7,8],[9,10],[11]]
Run Code Online (Sandbox Code Playgroud)

要交换每个块的元素,我们可以简单地调用reverse.所以最终的结果是:

Prelude Data.List.Split> let swap = concat . map reverse . chunk 2
Prelude Data.List.Split> swap [1..5]
[2,1,4,3,5]
Run Code Online (Sandbox Code Playgroud)