繁体   English   中英

Haskell,部分反转列表

[英]Haskell, reversing partially a list

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

我试图弄清楚,但是这是一个痛苦。

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

transf :: [a] -> [a]
transf [] = []
transf xs | length xs >= 4 = ???
          | otherwise = xs

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

通常,最好在使用length使用模式匹配。 例如,如果列表的长度是无限的,则length将永远循环。 因此,wen可以定义一个函数:

transf :: [a] -> [a]
transf (a:b:c:d:es) = ...
transf x = x

因此,在这里我们定义了一个模式(a:b:c:d:es) ,该模式用于定义一个至少包含四个元素( abcd )以及其余列表es的列表。

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

但是,我们可以在此处使用as模式,以匹配前两个项以及列表的其余部分(并且列表的其余部分应至少包含两个项目)。 喜欢:

transf :: [a] -> [a]
transf (a:b:cs@(_:_:_)) = b : a : ...
transf x = x

所以现在我们只需要填写... 这需要逆转最后两项。 与其让transf拥有所有的乐趣,我们可以定义一个新的功能swaplast :: [a] -> [a]其交换的最后一个项目。 如果列表没有两个元素,该怎么办可以由我们自己决定,因为我们知道调用该函数的列表将至少包含两个元素。 例如,我们可以决定简单地返回空列表和单例列表,而无需进行修改。 因此我们可以实现以下功能:

swaplast :: [a] -> [a]
swaplast [] = []
swaplast [a, b] = [b, a]
swaplast (a:bs) = a : swaplast bs

因此,我们获得了实现:

transf :: [a] -> [a]
transf (a:b:cs@(_:_:_)) = b : a : swaplast cs
transf x = x

swaplast :: [a] -> [a]
swaplast [] = []
swaplast [a, b] = [b, a]
swaplast (a:bs) = a : swaplast bs

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

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]

这样的事情只适用于有限列表

-- 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM