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