【发布时间】:2011-07-14 10:12:39
【问题描述】:
如何删除字符串的每个第 n 个元素?
我猜你会以某种方式使用drop 函数。
像这样丢弃第一个 n,你怎么能改变它,只丢弃第 n 个,然后是之后的第 n 个,依此类推,而不是全部?
dropthem n xs = drop n xs
【问题讨论】:
标签: haskell
如何删除字符串的每个第 n 个元素?
我猜你会以某种方式使用drop 函数。
像这样丢弃第一个 n,你怎么能改变它,只丢弃第 n 个,然后是之后的第 n 个,依此类推,而不是全部?
dropthem n xs = drop n xs
【问题讨论】:
标签: haskell
我喜欢以下解决方案:
del_every_nth :: Int -> [a] -> [a]
del_every_nth n = concat . map init . group n
您只需要定义一个函数group,它将一个列表分组为长度为n 的部分。但这很容易:
group :: Int -> [a] -> [[a]]
group n [] = []
group n xs = take n xs : group n (drop n xs)
【讨论】:
concatMap 而不是concat . map
remove_every_nth :: Int -> [a] -> [a]
remove_every_nth n = foldr step [] . zip [1..]
where step (i,x) acc = if (i `mod` n) == 0 then acc else x:acc
函数的作用如下:
zip [1..] 用于索引列表中的所有项目,例如zip [1..] "foo" 变为 [(1,'f'), (2,'o'), (3,'o')]。
然后使用right fold 处理索引列表,该right fold 会累积索引不能被n 整除的每个元素。
这里有一个稍长的版本,基本上做同样的事情,但避免了来自zip [1..] 的额外内存分配,并且不需要计算模数。
remove_every_nth :: Int -> [a] -> [a]
remove_every_nth = recur 1
where recur _ _ [] = []
recur i n (x:xs) = if i == n
then recur 1 n xs
else x:recur (i+1) n xs
【讨论】:
zip和mod,不如用cycle[1..n]和1比较?
remove_every_nth n = map snd . filter ((/= 0) . (`mod` n) . fst) . zip [1..]
zip,您将如何使用cycle,但我以不同的方式提高了效率。
cycle: removeEveryNth n = map snd . filter ((/= n) . fst) . (zip $ cycle [1..n])
\n l -> catMaybes $ zipWith (flip id) l $ cycle $ replicate (n-1) Just ++ [const Nothing]
简单。取 (n-1) 个元素,然后跳过 1 个,冲洗并重复。
dropEvery _ [] = []
dropEvery n xs = take (n-1) xs ++ dropEvery n (drop n xs)
为了效率,还是采用showS风格
dropEvery n xs = dropEvery' n xs $ []
where dropEvery' n [] = id
dropEvery' n xs = (take (n-1) xs ++) . dropEvery n (drop n xs)
【讨论】:
-- groups is a pretty useful function on its own!
groups :: Int -> [a] -> [[a]]
groups n = map (take n) . takeWhile (not . null) . iterate (drop n)
removeEveryNth :: Int -> [a] -> [a]
removeEveryNth n = concatMap (take (n-1)) . groups n
【讨论】:
尝试结合take 和drop 来实现这一点。
take 3 "hello world" = "hel"
drop 4 "hello world" = "o world"
【讨论】: