簡體   English   中英

通過折疊刪除無限列表中的連續重復項?

[英]Remove consecutive duplicates from an infinite list via folding?

考慮其中一個函數實現從列表中刪除連續的重復項:

uniq :: Eq a => [a] -> [a]
uniq [] = []
uniq (x:xs) = x:uniq (dropWhile (x ==) xs)
uniq :: Eq a => [a] -> [a]
uniq (x:xs@(y:_))
 | x == y    = x:tail (uniq xs)
 | otherwise = x:uniq xs
uniq l = l

它們都在有限列表和無限列表上都按預期工作。 更具體地說,對於無限列表,我希望只要在有n值返回之前沒有無限長的重復值序列,就會終止take n $ uniq l

現在考慮使用foldr進行這種函數的嘗試:

uniq :: (Foldable t, Eq a) => t a -> [a]
uniq = foldr uniqHelper []
 where uniqHelper x [] = [x]
       uniqHelper x acc@(y:_)
        | x == y    =   acc
        | otherwise = x:acc

這在有限列表上正常工作,但永遠不會終止無限列表,因為uniqHelper總是需要評估它的第二個參數。 這是一個可以用更聰明的uniqHelper修復的東西,還是本來就不可能使用折疊來完成這項任務?

你可以將一個元素的移除轉移到尾部,所以無論值是什么,我們首先“ 產生x ,然后我們使用一個函數(這里是tl )來評估列表的尾部:

uniq :: (Foldable t, Eq a) => t a -> [a]
uniq = foldr uniqHelper []
 where uniqHelper x acc = x : tl acc
           where tl acc@(x2:xs) | x == x2 = xs
                                | otherwise = acc
                 tl [] = []

因此,我們首先產生x ,然后擔心下一個元素。 如果第二個參數(列表尾部的折疊列表)包含相同的元素,那么我們“刪除”它,否則,我們保留整個列表。

以上也能夠產生repeat的第一個元素,例如:

Prelude> head (uniq (repeat 1))
1
Prelude> take 5 $ uniq [1..]
[1,2,3,4,5]
Prelude> uniq [1,1,1,1,2,2,2,1,1,1,1,1,1,3,3,3,3,1,1]
[1,2,1,3,1]

當然,如果有無限量的0秒后跟1 ,則永遠不會發出1

Prelude> uniq (repeat 0 ++ [1])
[0

你的第一個片段產生了許多的第一個x,但第三個片段產生了最后的x,這就是差異的原因。

為了忠實地將第一個片段呈現為右側折疊,我們將其折疊為函數,以便我們可以傳遞狀態參數,偶爾更新到列表的新唯一元素:

uniq [] = []
uniq (x:xs) = x : foldr g (const []) xs x
  where
  g y r x | y==x  =     r x
      | otherwise = y : r y

這實際上是跳過重復而不是重新進行,然后在其他兩個答案正在進行時一遍又一遍地忽略它們,這實際上是彼此等同的: dropWhile只能跳過不超過一個元素,這將是通過下面的減速器調用跳過dropWhile (==x)

ecursive esult". 我總是使用r作為reducer的第二個參數的名稱,作為“ ecursive esult”的助記設備。 這里經過又一參數的存在rg的定義是指r是一個函數,我們可以通過更新的值作為狀態。

此技術允許使用foldr編碼有狀態計算,如takedropdropWhiletakeWhile

 > head $ uniq $ repeat 1 1 > take 10 $ uniq [n | n <- [1..], n <- replicate nn] [1,2,3,4,5,6,7,8,9,10] > uniq [1..10] [1,2,3,4,5,6,7,8,9,10] 

您可以組合您的實現:

uniq :: Eq a => [a] -> [a]
uniq = foldr uniqHelper []
  where uniqHelper x acc = x : dropWhile (==x) acc

在無限列表上獲得所需的行為:

Prelude> take 5 $ uniq [1..]
[1,2,3,4,5]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM