【发布时间】:2017-06-11 19:47:36
【问题描述】:
所以我需要从给定列表中提取具有另一个列表中给出的索引的元素。 签名应该是这样的:
search :: [Int] -> [a] -> [a]
结果
search [1,3,5] [34,65,67,34,23,43,54]
[65,34,43]
据我所知,这没有标准函数,我可以在更常见的带有循环的语言上做到这一点,但我对 haskell 不太擅长。
【问题讨论】:
所以我需要从给定列表中提取具有另一个列表中给出的索引的元素。 签名应该是这样的:
search :: [Int] -> [a] -> [a]
结果
search [1,3,5] [34,65,67,34,23,43,54]
[65,34,43]
据我所知,这没有标准函数,我可以在更常见的带有循环的语言上做到这一点,但我对 haskell 不太擅长。
【问题讨论】:
假设索引已排序,您可以编写自己的显式递归。
search :: [Int] -> [a] -> [a]
search indices xs = go indices 0 xs -- start from index 0
where
go :: [Int] -> Int -> [a] -> [a]
-- no more indices, we are done
go [] _ _ = []
-- more indices but no more elements -> error
go _ _ [] = error "index not found"
-- if the wanted index i is the same as the current index j,
-- return the current element y, more to the next wanted index
go (i:is) j yys@(y:_) | i==j = y : go is j yys
-- otherwise, skip y and increment the current index j
go iis j (_:ys) = go iis (j+1) ys
存在更多高级方法,但这应该是一种基本的有效替代方法。它在 O(n) 中运行,其中 n 是列表的长度。
请注意,重复调用 !! 将需要 O(n^2) 时间,因为每个 !! 花费 O(n)。
如果索引未排序,请改用go (sort indices) 0 xs。成本增加到 O(n log n)。
【讨论】:
可以使用(!!) :: [a] -> Int -> Int 运算符和列表推导来实现:
search :: [Int] -> [a] -> [a]
search js xs = [xs!!j | j <- js]
但是(!!) 运算符在 O(k) 中工作,而 k 是请求的索引,所以这将是低效的。
鉴于索引列表是有序且不会超出范围,纯 Haskell 函数可能如下:
search :: [Int] -> [a] -> [a]
search = search' 0
where search' _ [] _ = []
search' i (j:js) xs = y : search' (j+1) js ys
where (y:ys) = drop (j-i) xs
【讨论】:
您可以像这样使用!! operator 访问列表的元素:
List!!index == value_at_that index
因此,您的函数可能如下所示:
search indexes list = [list!!x | x <- indexes]
【讨论】:
!!。
Vector 或 IntMap)并从中查找索引,而不是值列表本身.
!! 操作员只是想不通如何在这里正确使用它。据我所知,索引总是按升序排列,但是可以说存在“差距”。他们不应该越界。