Haskell,部分反转了一个列表

时间:2018-01-09 19:27:13

标签: list haskell reverse

我正在尝试创建一个带有列表的函数,如果列表的长度至少为4,则它会反转所述列表的第一个和第二个元素以及最后两个元素。 想象一下输入是[1,2,3,4,5,6]这应该给我[2,1,3,4,6,5]。

我想弄明白,但这对屁股很痛苦。

所以,这就是我所拥有的:

tasker called for 0
Task[MyTask0][started]
[queuedTasks$][next]: Task[MyTask0][0%]
tasker called for 1
Task[MyTask0][started]
[queuedTasks$][next]: Task[MyTask0][20.688413934455674%]
[queuedTasks$][next]: Task[MyTask0][32.928520335195564%]
[queuedTasks$][next]: Task[MyTask0][42.58361384849108%]
[queuedTasks$][next]: Task[MyTask0][73.1297043008671%]
[queuedTasks$][next]: Task[MyTask0][100%]
tasker called for 2
Task[MyTask1][started]
[queuedTasks$][next]: Task[MyTask1][0%]
tasker called for 3
Task[MyTask1][started]
[queuedTasks$][next]: Task[MyTask1][37.16513927245511%]
[queuedTasks$][next]: Task[MyTask1][47.27771448102375%]
[queuedTasks$][next]: Task[MyTask1][60.45983311604027%]
[queuedTasks$][next]: Task[MyTask1][100%]
tasker called for 4
Task[MyTask2][started]
[queuedTasks$][next]: Task[MyTask2][0%]
tasker called for 5
Task[MyTask2][started]
[queuedTasks$][next]: Task[MyTask2][32.421275902708544%]
[queuedTasks$][next]: Task[MyTask2][41.30332084025583%]
[queuedTasks$][next]: Task[MyTask2][77.44113197852694%]
[queuedTasks$][next]: Task[MyTask2][100%]
[queuedTasks$][complete] Complete

所以我认为我可以做一个只能反转那些元素然后在transf函数上调用它的aux函数。 有什么帮助吗?

3 个答案:

答案 0 :(得分:7)

通常使用模式匹配比使用setx /M PHP_PATH {path to php here} 更好。例如,如果列表具有无限长度,length将永远循环。所以wen可以定义一个函数:

length

所以我们在这里定义一个模式transf :: [a] -> [a] transf (a:b:c:d:es) = ... transf x = x ,它是定义一个至少包含四个元素的列表的模式((a:b:c:d:es)ab和{{1 }}和列表的其余部分c

现在在这种情况下,我们知道我们必须反转列表的前两个元素,因此结果类似于d。现在的问题是我们如何计算列表的其余部分。我们无法将esb : a : ...添加到列表中,因为c可能是空列表,在这种情况下,我们要反转d和{{ 1}}。这可能导致很多情况。

然而,我们可以在这里使用as-pattern来匹配前两个项目以及列表的其余部分(列表的其余部分应该包含至少两个项目)。像:

es

所以现在我们只需要填写d。这需要反转最后两项。我们可以定义一个新的函数c来交换最后的项目,而不是让transf :: [a] -> [a] transf (a:b:cs@(_:_:_)) = b : a : ... transf x = x 拥有所有的乐趣。如果列表没有两个元素该怎么办可以由我们自己决定,因为我们知道我们将调用该函数的列表将至少有两个元素。例如,我们可以决定只返回空列表和单例列表而不进行修改。所以我们可以实现这样的功能:

...

然后我们获得实现:

transf

答案 1 :(得分:4)

我们写了四个功能。这使得推理变得更加简单,并且功能更易于维护:

reverseFirst :: [a] -> [a]
reverseFirst (x:y:xs) = y : x : xs
reverseFirst xs       = xs

reverseLast :: [a] -> [a]
reverseLast [x, y] = [y, x]
reverseLast (x:xs) = x : reverseLast xs
reverseLast xs     = xs

lengthAtLeast :: [a] -> Int -> Bool
lengthAtLeast xs n = not $ null $ drop (n - 1) xs

现在,有了这些助手,很容易编写第四个也是最后一个函数:

transf :: [a] -> [a]
transf xs
  | xs `lengthAtLeast` 4 = reverseLast $ reverseFirst xs
  | otherwise           = xs

如果模式匹配,我们可以删除lengthAtLeast

transf :: [a] -> [a]
transf (a:b:xs@(_:_:_)) = b : a : reverseLast xs
transf xs               = xs

运动

最后反转字符数量并开始自定义:

transform :: Int -> Int -> [a] -> [a]
transform = ...

它应该像这样工作:

transform 1 1 [1,2,3,4] = [1,2,3,4]
transform 1 2 [1,2,3,4] = [1,2,4,3]
transform 1 3 [1,2,3,4] = [1,4,3,2]
transform 1 4 [1,2,3,4] = [1,2,3,4] -- list isn't 5 elements long
transform 2 2 [1,2,3,4] = [2,1,4,3]

答案 2 :(得分:0)

像这样的东西,仅适用于有限列表

-- works only for finite lists
f :: [a] -> [a]
f ls
    | n <= 4     = ls
    | otherwise  = let (a:b:hs, [x, y]) = splitAt (n - 2) ls 
                   in  b:a:(hs ++ [y, x])
    where
        n = length ls