使用Int(Haskell)列表删除列表中的元素

时间:2016-09-08 13:48:58

标签: list haskell

我正在编写一个函数,该函数采用Int列表,一般类型a的列表,并删除Int列表中具有索引的所有元素。

例如:removeEl [1,3,4] [1,2,3,4,5,6]返回[1,3,6]removeEl [1,2] "Firefox"返回"Fefox"

这是我的尝试:

removeEl :: [Int] -> [a] -> [a]
removeEl [] xs = []
removeEl ns [] = []
removeEl (n:ns) (x:xs) | n == 0 = removeEl ns xs
                       | n > 0 = x:removeEl (n-1) xs

我意识到(n-1)Int,而不是[Int]所以它失败了。我是否需要编写辅助功能才能使用?

2 个答案:

答案 0 :(得分:3)

您需要传递一个新列表,但该列表中的每个项目都需要递减,因为您已经移动了第二个参数的每个元素的位置。无论您是否实际移除了头元素,都是如此。

removeEl (n:ns) (x:xs) | n == 0 = removeEl (map pred ns) xs
                       | n > 0 = x:removeEl (map pred (n:ns)) xs

有很多机会重构这一点,但我玩过的任何东西都没那么简单。

此外,您的第一个基本案例是错误的:索引列表中没有项目,您想要返回所有内容,而不是没有

remove [] xs = xs

(请记住,只有当第一个参数单调递增时,这才有效。)

您还可以使用列表解析来避免显式递归:

removeEl ns xs = [x | (n,x) <- zip [0..] xs, not(n `elem` ns)]

答案 1 :(得分:3)

我相信您的算法是O(n*m),其中n是列表中元素的数量,m是要删除的索引数。它还有一个不幸的要求,即必须订购指数清单。这是一个~O(n*log(m))解决方案,不需要订购索引。

import qualified Data.Set as Set

removeE1 indices xs = go 0 xs
  where is = Set.fromList indices
        go _ [] = []
        go n (y:ys) | n `Set.member` is = go (n+1) ys
                    | otherwise         = y : go (n+1) ys

使用哈希映射可以稍微改善一下。