簡體   English   中英

Haskell - 過濾元組列表

[英]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 的建議使用breakspan 你需要一個謂詞。 您可以使用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.

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