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
4条答案
按热度按时间csga3l581#
假设索引是排序的,您可以编写自己的显式递归。
这是一个复杂度为O(n)的过程,其中n是列表的长度,而n是列表的长度,所以这个过程的时间复杂度为O(n)。
注意,重复调用
!!
将需要O(n^2)的时间,因为每个!!
花费O(n)。时间复杂度为O(n log n),因此,时间复杂度为O(n log n)。
643ylb082#
我们可以使用
(!!) :: [a] -> Int -> Int
运算符和 list comprehension 来实现这一点,如下所示:但是
(!!)
操作符在 O(k) 中工作,k 是请求的索引,所以这将是低效的。给定索引列表是有序的并且没有超出界限,纯Haskell函数可以是如下:
ovfsdjhp3#
可以使用
!!
operator访问列表的元素,如下所示:因此,您的函数可能如下所示:
6fe3ivhb4#
基于库的解决方案:
当面对这类Haskell工作时,为它找到一个合适的库函数通常是一个好主意。与临时手动递归不同,可以信任正式的库函数与Haskell运行时系统的特性平滑地交互。
在这里,手头的工作似乎非常适合
unfoldr
库函数:unfoldr
函数采用a)初始 * 状态 * 和B)* 状态转移函数 *,其产生(可能)新状态以及输出值。这里,该状态可以由包含以下的三元组组成:
1.初始值列表的深度
1.索引列表的剩余部分
1.值列表的剩余部分
作为预备步骤,我们暂时假设索引列表是有序的,因此我们可以以线性方式处理两个列表(下面将进一步解除该限制)。
这将给出以下代码:
测试:
这是可行的。现在我们来看看如何解除有序索引的限制。
允许无序的索引列表:
这里的想法是对索引列表进行 * 排序 *,但要以一种跟踪任何给定索引在初始列表中所占 * 排名 * 的方式来进行。
因此,我们可以编写一个
search2p
辅助函数,该函数生成所请求的值,但与它们对应的索引排名配对。接下来,我们提供一个search2
Package 函数,该函数恢复初始索引顺序并丢弃排名信息:**注意:**这类似于某些圈子中称为decorate-sort-undecorate paradigm的技术。
测试: