想知道如何在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
但必须有更优雅的东西吗?
感谢。
答案 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]