簡體   English   中英

Haskell函數可保留列表的重復元素

[英]Haskell function to keep the repeating elements of a list

這是預期的輸入/輸出:

重復的“密西西比州” ==“ ips”

重復[1,2,3,4,2,5,6,7,1] == [1,2]

重復“” ==“”

到目前為止,這是我的代碼:

repeated :: String -> String
repeated "" = "" 
repeated x = group $ sort x 

我知道代碼的最后一部分不起作用。 我當時正在考慮對列表進行排序,然后將其分組,然后我想對大於1或類似名稱的列表進行過濾。

您的代碼已經完成了一半的工作

> group $ sort "Mississippi"
["M","iiii","pp","ssss"]

您說過要過濾掉重復項。 讓我們定義一個謂詞,該謂詞標識具有至少兩個元素的列表:

atLeastTwo :: [a] -> Bool
atLeastTwo (_:_:_) = True
atLeastTwo _       = False

使用這個:

> filter atLeastTwo . group $ sort "Mississippi"
["iiii","pp","ssss"]

好。 現在,我們只需要從此類列表中獲取第一個元素。 由於列表是非空的,因此我們可以安全地使用head

> map head . filter atLeastTwo . group $ sort "Mississippi"
"ips"

或者,我們可以用filter (\\xs -> length xs >= 2)替換該過濾器,但這會降低效率。

另一個選擇是使用列表理解

> [ x | (x:_y:_) <- group $ sort "Mississippi" ]
"ips"

此模式在以x開頭並至少具有另一個元素_y的列表上匹配,將過濾器與獲取頭部組合在一起。

好的,好的開始。 一個直接的問題是,規范要求該函數在數字列表上起作用,但是您為字符串定義了該函數。 該列表必須排序,因此其元素必須具有Typeclass Ord 因此,讓我們修復類型簽名:

repeated :: Ord a => [a] -> [a]

調用sort and group ,您將獲得一個列表列表[[a]] 讓我們來考慮使用filter的想法。 這樣可行。 如您所說,謂詞應檢查列表中每個列表的length ,然后將該length與1進行比較。

過濾列表列表將為您提供一個[[a]]類型的子集,這是列表的另一個列表。 您需要展平此列表。 您要做的是將列表列表中的每個條目map到其元素之一。 例如第一個。 Prelude有一個功能可以做到這一點。

因此,您可以填寫以下框架:

module Repeated (repeated) where

import Data.List (group, sort)

repeated :: Ord a => [a] -> [a]
repeated = map _
         . filter (\x -> _)
         . group
         . sort 

我已經以無謂樣式編寫了此內容,並將過濾謂詞作為lambda表達式編寫,但是其他許多編寫方法也同樣不錯。 找到您喜歡的一個! (例如,您還可以以無點形式編寫filter謂詞,由兩個函數組成:對length結果的比較。)

當您嘗試對此進行編譯時,編譯器將告訴您,有兩個類型的孔 ,即等號右邊的_條目。 它還會告訴您孔的類型。 第一個孔需要一個函數,該函數需要一個列表並為您提供單個元素。 第二個孔需要使用x的布爾表達式。 正確填寫這些內容,您的程序將運行。

這是使用group $ sort評估@chepner對解決方案的評論的其他方法。 (這些解決方案看起來更簡單,因為某些復雜性隱藏在庫例程中。)

的確排序是O(n lg n),...

使用span的不僅是排序,而且尤其是group :它們都可以構建和銷毀臨時列表。 即他們這樣做:

線性遍歷未排序列表將需要一些其他數據結構來跟蹤所有可能的重復項,並且在每個表中進行查找將至少增加空間的復雜性。 雖然可以使用精心選擇的數據結構來維持總體O(n)運行時間,但該常數可能會使算法在實踐中比O(nlg n)解決方案更慢,...

group/span大大增加了該復雜度,因此O(n lg n)不是正確的度量。

同時大大簡化了實現。

以下所有內容僅遍歷輸入列表一次。 是的,他們建立了輔助清單。 (可能是Set可以提供更好的性能/快速查找。)它們看起來可能更復雜,但是要比較apples和apples,還要查看group/span的代碼。

repeated2, repeated3, repeated4 :: Ord a => [a] -> [a]
  • repeated2/inserter2建立了一個輔助對列表[(a, Bool)] ,如果a出現多次,則BoolTrue如果到目前為止僅一次,則BoolFalse

     repeated2 xs = sort $ map fst $ filter snd $ foldr inserter2 [] xs inserter2 :: Ord a => a -> [(a, Bool)] -> [(a, Bool)] inserter2 x [] = [(x, False)] inserter2 x (xb@(x', _): xs) | x == x' = (x', True): xs | otherwise = xb: inserter2 x xs 
  • repeated3/inserter3構建[(a, Int)]對的輔助列表,其中Int計算出現的a 輔助列表無論如何都只是為了它的排序而排序。

     repeated3 xs = map fst $ filter ((> 1).snd) $ foldr inserter3 [] xs inserter3 :: Ord a => a -> [(a, Int)] -> [(a, Int)] inserter3 x [] = [(x, 1)] inserter3 x xss@(xc@(x', c): xs) = case x `compare` x' of { LT -> ((x, 1): xss) ; EQ -> ((x', c+1): xs) ; GT -> (xc: inserter3 x xs) } 
  • repeated4/go4構建已知重復的元素的輸出列表。 它遍歷輸入列表時維護了一次(到目前為止)遇到的元素的中間列表。 如果遇到重復:將其添加到輸出列表; 從中間列表中刪除它; 從輸入列表的末尾過濾該元素。

     repeated4 xs = sort $ go4 [] [] xs go4 :: Ord a => [a] -> [a] -> [a] -> [a] go4 repeats _ [] = repeats go4 repeats onces (x: xs) = case findUpd x onces of { (True, oncesU) -> go4 (x: repeats) oncesU (filter (/= x) xs) ; (False, oncesU) -> go4 repeats oncesU xs } findUpd :: Ord a => a -> [a] -> (Bool, [a]) findUpd x [] = (False, [x]) findUpd x (x': os) | x == x' = (True, os) -- ie x' removed | otherwise = let (b, os') = findUpd x os in (b, x': os') 

    findUpd最后的列表findUpdspan非常相似。)

暫無
暫無

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

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