过滤统一列表列表

时间:2014-09-08 16:37:32

标签: haskell

我一直试图找到这个问题的解决方案,现在已经有几天了,在我对自己太沮丧之前,我决定寻求帮助。

我有一份统一名单清单,例如: [[2], [2, 2], [3], [3, 3] [3, 3, 3], [5]]我希望应用过滤器,以便只保留不属于任何其他列表子集的列表。

那是一个复杂的句子。基本上我需要一个函数f

f [[2], [2, 2], [3], [3, 3] [3, 3, 3], [5]]

结果

[[2, 2], [3, 3, 3], [5]]

我希望我已经清楚了。如果没有,请帮我澄清一下!

3 个答案:

答案 0 :(得分:2)

假设您的列表都是统一的,因为没有列表包含两个不同的元素(即[2, 3]),您可以用长度来表示这个问题:

> import Control.Arrow
> -- Equivalent to `\x -> (head x, length x)`
> :t head &&& length
head &&& length :: [a] -> (a, Int)
> (head &&& length) [2, 2, 2]
(2, 3)
>
> let myData = <what you have above>
> map (head &&& length) myData
[(2, 1), (2, 2), (3, 1), (3, 3), (5, 1)]

现在您可以按第一个元素分组

> import Data.List
> :t groupBy
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
> import Data.Function
> :t on
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
> :t on (==) fst
on (==) fst :: Eq b => (b, b1) -> (b, b1) -> Bool
> :t groupBy (on (==) fst)
groupBy (on (==) fst) :: Eq b -> [(b, b1)] -> [[(b, b1)]]
> groupBy (on (==) fst) $ map (head &&& length) myData
[[(2,1),(2,2)],[(3,1),(3,2),(3,3)],[(5,1)]]

然后,您可以选择最大snd的字词:

> :t maximumBy
maximumBy :: (a -> a -> Ordering) -> [a] -> a
> import Data.Ord
> :t comparing
comparing :: Ord a => (b -> a) -> b -> b -> Ordering
> :t comparing snd
comparing snd :: Ord a => (a1, a) -> (a1, a) -> Ordering
> :t maximumBy (comparing snd)
maximumBy (comparing snd) :: Ord a -> [(a1, a)] -> (a1, a)
> :t map (maximumBy (comparing snd))
map (maximumBy (comparing snd)) :: Ord a => [[(a1, a)]] -> [(a1, a)]
> map (maximumBy (comparing snd)) $ groupBy (on (==) fst) $ map (head &&& length) myData
[(2, 2), (3, 3), (5, 1)]

现在,如果您愿意,可以使用replicate将其转换回列表:

> map (uncurry (flip replicate)) $ map (maximumBy (comparing snd)) $ groupBy (on (==) fst) $ map (head &&& length) myData
[[2, 2], [3, 3, 3], [5]]

最终功能看起来像

import Data.List (groupBy, maximumBy)
import Data.Ord (comparing)
import Data.Function (on)
import Control.Arrow ((&&&))

biggestUnique :: [[Int]] -> [[Int]]
biggestUnique
    = map     (uncurry   (flip replicate))   -- Convert back to lists
    . map     (maximumBy (comparing snd))    -- Select by the maximum length
    . groupBy ((==) `on` fst)                -- Group by the element value
    . map     (head &&&  length)             -- Reformulate in terms of length

你可以将map压缩成一个,但我认为这会降低它的可读性。

警告:如果元素在每个子列表中不唯一,则无法正常工作。

答案 1 :(得分:2)

看起来你想要这个:

import Data.List
import Data.Function

f :: (Ord a) => [[a]] -> [[a]]
f = map (maximumBy (compare `on` length)) . groupBy ((==) `on` head) . sortBy (compare `on` head)

我们只是将列表按其头部分组并选择每个列表的最大值。

如果我不理解你错了,你想要选择不是其他列表的子列表的列表,这实际上是每个组的最长列表。

答案 2 :(得分:1)

没有列表是空列表的正确子列表。空列表是每个非空列表的正确子列表。

import Data.List (delete)

sublist :: Eq a => [a] -> [a] -> Bool
sublist _        []               = False
sublist []       _                = True
sublist (x : xs) ys | x `elem` ys = sublist xs (delete x ys)
                    | otherwise   = False

使用none pred = not . any pred,但没有Ord约束:

superlists :: Eq a => [[a]] -> [[a]]
superlists xss = filter (\ xs -> none (xs `sublist`) xss) xss

含义

superlists [[1,2,2],[2,2,1],[1],[]]  ==  [[1,2,2],[2,2,1]]

superlists [[2],[2,2],[3],[3,3],[3,3,3],[5]]  ==  [[2,2],[3,3,3],[5]]

具有内容相当的替代sublist

elemDelete :: Eq a => a -> [a] -> (Bool, [a])
elemDelete _ []                   = (False, [])
elemDelete y (x : xs) | x == y    = (True, xs)
                      | otherwise = let (b, zs) = elemDelete y xs
                                    in  (b, x : zs)

sublist :: Eq a => [a] -> [a] -> Bool
sublist _        [] = False
sublist []       _  = True
sublist (x : xs) ys = let (b, dys) = elemDelete x ys
                      in  if b then sublist xs dys 
                               else False

elemDelete y xs实际上效率低于(elem y xs, delete y xs)