[英]Haskell - Filtering a list of tuples
考慮這個元組列表:
[(57,48),(58,49),(59,50),(65,56),(65,47),(65,57),(65,49), (41, 11)]
我想刪除一個元組(a, b)
如果它的第二個元素b
等於另一個元組的第一個元素以及它之后的所有具有相同a
的元組。 例如:
(65,57)
的第二個元素是 57 並且列表(57,48)
的第一個元組有 57 作為它的第一個元素,所以(65,57)
應該被刪除,並且在它之后的所有元組以 65 開頭,即(65,49)
。 在它之前的元組(65,56)
和(65,47)
應該留在列表中。
有誰知道如何做到這一點?
為了提高效率(單次傳遞),您應該創建兩個集合,一個用於您已將其視為元組的第一個元素的元素,另一個用於您已將其視為第一個和第二個元素的元素(即如果匹配第一個元素則刪除) .
就像是,
{-# LANGUAGE PackageImports #-}
import "lens" Control.Lens (contains, (.~), (^.), (&))
import "yjtools" Data.Function.Tools (applyUnless, applyWhen)
import qualified "containers" Data.IntSet as Set
filterTuples :: Foldable t => t (Int, Int) -> [(Int, Int)]
filterTuples = flip (foldr go $ const []) (Set.empty, Set.empty)
where
go p@(x,y) go' (fsts, deletes) =
let seenFst = fsts ^. contains y
shouldDelete = seenFst || deletes ^. contains x
fsts' = fsts & contains x .~ True
deletes' = deletes & applyWhen seenFst (contains y .~ True)
in applyUnless shouldDelete (p:) $ go' (fsts', deletes')
編輯:為了正確性,清晰度,脊柱懶惰
您可以從創建所有第一個元素的不同集合開始,例如:
Prelude Data.List> firsts = nub $ fst <$>
[(57,48),(58,49),(59,50),(65,56),(65,47),
(65,57),(65,49), (41, 11)]
Prelude Data.List> firsts
[57,58,59,65,41]
您可以按照 Robin Zigmond 的建議使用break
或span
。 你需要一個謂詞。 您可以使用elem
,如下所示:
Prelude Data.List> elem 48 firsts
False
Prelude Data.List> elem 49 firsts
False
...
Prelude Data.List> elem 57 firsts
True
如果您擔心elem
效率太低,您可以嘗試創建一個Set並改用member
函數。
我是haskell的絕對初學者,因此可能有一個更優雅/更有效的解決方案。 但無論如何我想分享我想出的解決方案:
filterTuples :: [(Int, Int)] -> [(Int,Int)]
filterTuples [] = []
filterTuples (x:xs) = x:filterTuples(concat ((fst temp) : [filter (\z -> fst z /= del) (snd temp)]))
where del = fst (head (snd temp))
temp = break (\y -> (snd y == fst x)) xs
(很高興就如何改進這一點提供反饋)
也許嘗試使用mapAccumL
從初始列表開始作為累加器。 然后維護一個Predicate
作為參數,它作為已看到內容的決定器,這將確定您是否可以在遍歷的每一步輸出。
f
消耗對列表: xs
; 它生成一個新的對列表: ys
。 ys
包含xs
中的每一對: (a, b)
,除了第二個元素b
:先前作為第一個元素出現的對: a
。 當遇到這樣的對: (a, b)
時,將a
作為其第一個元素的后續對從ys
中排除。
f xs = go xs [] []
where
go [] ys zs = ys
go (x@(a,b):xs) ys zs
| b `elem` as = go xs ys (a:zs)
| a `elem` zs = go xs ys zs
| otherwise = [x] ++ go xs ys zs
as = (nub . fst . unzip) xs
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.