删除Seq中的重复元素

时间:2017-08-18 13:26:23

标签: haskell

想知道如何在nub

上实施Seq a

我得到的可以做到:

nubSeq :: Seq a -> Seq a
nubSeq = fromList . nub . toList

只是想知道有什么标准不会转换为列表来调用nub :: [a]->[a]吗?

基于nub,我发现的一个实现是:

nubSeq :: (Eq a) => Seq a -> Seq a
nubSeq = Data.Sequence.foldrWithIndex 
           (\_ x a -> case x `Data.Sequence.elemIndexR` a of
                        Just _ -> a
                        Nothing -> a |> x) Data.Sequence.empty 

但必须有更优雅的东西吗?

感谢。

3 个答案:

答案 0 :(得分:4)

不确定这是否更符合优雅,但它会将问题分散到独立函数中(警告:library(data.table) set.seed(1) DT = data.table( group=sample(letters[1:2],100,replace=TRUE), year=sample(2010:2012,100,replace=TRUE), v=runif(100)) cube(DT, mean(v), by=c("group","year")) # group year V1 # 1: a 2011 0.4176346 # 2: b 2010 0.5231845 # 3: b 2012 0.4306871 # 4: b 2011 0.4997119 # 5: a 2012 0.4227796 # 6: a 2010 0.2926945 # 7: NA 2011 0.4463616 # 8: NA 2010 0.4278093 # 9: NA 2012 0.4271160 #10: a NA 0.3901875 #11: b NA 0.4835788 #12: NA NA 0.4350153 cube(DT, mean(v), by=c("group","year"), id=TRUE) # grouping group year V1 # 1: 0 a 2011 0.4176346 # 2: 0 b 2010 0.5231845 # 3: 0 b 2012 0.4306871 # 4: 0 b 2011 0.4997119 # 5: 0 a 2012 0.4227796 # 6: 0 a 2010 0.2926945 # 7: 2 NA 2011 0.4463616 # 8: 2 NA 2010 0.4278093 # 9: 2 NA 2012 0.4271160 #10: 1 a NA 0.3901875 #11: 1 b NA 0.4835788 #12: 3 NA NA 0.4350153 上需要Ord约束):

  • a获取seqToNubMap并输出Seq与每个Map相关联的最小索引

  • a获取mapToList个值和位置,并根据指定的位置按递增顺序生成值列表

  • Map将这些组合起来生成一个没有重复的序列

整个事情应该是O(n * log(n)),我相信:

nubSeq

或者@ DavidFletcher评论之后的更简单的替代方案:

module NubSeq where

import Data.Map      as Map
import Data.List     as List
import Data.Sequence as Seq
import Data.Function

seqToNubMap :: Ord a => Seq a -> Map a Int
seqToNubMap = foldlWithIndex (\ m k v -> insertWith min v k m) Map.empty

mapToList :: Ord a => Map a Int -> [a]
mapToList = fmap fst . List.sortBy (compare `on` snd) . Map.toList

nubSeq :: Ord a => Seq a -> Seq a
nubSeq = Seq.fromList . mapToList . seqToNubMap

答案 1 :(得分:0)

使用Ord约束的另一种方法 - 使用扫描来制作集合 出现在列表的每个前缀中的元素。然后我们可以过滤掉 任何已经看过的元素。

import Data.Sequence as Seq
import Data.Set as Set

nubSeq :: Ord a => Seq a -> Seq a
nubSeq xs = (fmap fst . Seq.filter (uncurry notElem)) (Seq.zip xs seens)
  where
    seens = Seq.scanl (flip Set.insert) Set.empty xs

或者与mapAccumL大致相同:

nubSeq' :: Ord a => Seq a -> Seq a
nubSeq' = fmap fst . Seq.filter snd . snd . mapAccumL f Set.empty
  where
    f s x = (Set.insert x s, (x, x `notElem` s))

(如果我使用的是列表,我会使用Maybes代替配对 Bool,然后使用catMaybes而不是过滤。似乎没有catMaybes 对于序列。)

答案 2 :(得分:-1)

我认为您的代码应该非常高效。由于Sequences是树数据结构,使用另一种树类型数据结构(如Map或HashMap)来存储和查找以前的项目对我来说没有多大意义。

相反,我拿第一个项目并检查其余部分是否存在。如果存在,我将删除该项目,并以递归方式继续执行相同的操作。如果没有则构造一个新的序列,第一个元素是唯一元素,其余元素是由其余元素提供的nubSeq的结果。应该是典型的。我使用ViewPatterns。

{-# LANGUAGE ViewPatterns #-}
import Data.Sequence as Seq

nubSeq :: Eq a => Seq a -> Seq a
nubSeq (viewl -> EmptyL)    = empty
nubSeq (viewl -> (x :< xs)) | elemIndexL x xs == Nothing = x <| nubSeq xs
                            | otherwise                  = nubSeq xs

*Main> nubSeq . fromList $ [1,2,3,4,4,2,3,6,7,1,2,3,4]
fromList [6,7,1,2,3,4]