如何创建“计数”过滤器?

时间:2015-03-04 12:51:03

标签: haskell

我有一个对列表,我需要一个过滤器,它只保留对中第一个成员至少出现两次的元素:

someFilter :: Eq a => [(a, b)] -> [(a, b)]
someFilter   [("a",1),("a",2),("b",1)]
  `shouldBe` [("a",1),("a",2)]         -- "a" occurs in two pairs, retain both

someFilter   [("a",1),("a",2),("b",1),("b",2)]
  `shouldBe` [("a",1),("a",2),("b",1),("b",2)] -- "a" and "b" occur twice

someFilter   [("a",1),("b",2),("c",1),("d",2)]
  `shouldBe` [] -- no string occurs twice

我不确定如何实现这样的过滤器。通常的filter只能在元素方面起作用。如何写someFilter

2 个答案:

答案 0 :(得分:5)

您可以首先按元组的第一个元素对元组进行分组,然后连接至少包含两个元素的组。此解决方案不是O(n ^ 2),但强加Ord约束。

import Data.List (groupBy, sortBy)
import Data.Function (on)
import Data.Ord (comparing)

someFilter :: Ord a => [(a, b)] -> [(a, b)]
someFilter = concat
           . filter ((>= 2) . length)
           . groupBy ((==) `on` fst)
           . sortBy (comparing fst)

答案 1 :(得分:0)

正如其他答案,已经说过,您需要对列表进行分组。显而易见的候选人与使用Data.List.groupBy的Frerich解决方案一样,但是,我经常发现创建地图更容易(您不需要排序)。

import qualified Data.Map as M

someFilter xs = M.keys $ M.filter (>=1) 
                                  (M.fromList (+) [(x,1) | (x,_) <- xs])