2011-11-13 147 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] 
相关问题