我有一个对列表,我需要一个过滤器,它只保留对中第一个成员至少出现两次的元素:
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
?
答案 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])