有效地找到列表的最大值索引

时间:2012-02-14 01:21:51

标签: list haskell functional-programming

编辑:我一定不能说清楚,但我正在寻找一个之类的函数,但不完全正确。

给定一个列表,我希望能够找到列表中最大元素的索引 (所以,list !! (indexOfMaximum list) == maximum list
我写了一些看似非常高效的代码,虽然我觉得我正在重新发明轮子。

indexOfMaximum :: (Ord n, Num n) => [n] -> Int
indexOfMaximum list =
   let indexOfMaximum' :: (Ord n, Num n) => [n] -> Int -> n -> Int -> Int
       indexOfMaximum' list' currIndex highestVal highestIndex
          | null list'                = highestIndex
          | (head list') > highestVal = 
               indexOfMaximum' (tail list') (1 + currIndex) (head list') currIndex
          | otherwise                 = 
               indexOfMaximum' (tail list') (1 + currIndex) highestVal highestIndex
   in indexOfMaximum' list 0 0 0

现在我想返回列表中最大n个数字的索引列表。

我唯一的解决方案是将前n个元素存储在列表中,并将(head list') > highestVal替换为n个最大的列表中的比较。

感觉必须有一种比这更有效的方式,我也觉得我没有充分利用Prelude和Data.List。有什么建议?

3 个答案:

答案 0 :(得分:5)

最短路径找到最大元素的最后一个索引

maxIndex list = snd . maximum $ zip list [0 .. ]

如果你想要第一个索引,

maxIndex list = snd . maximumBy cmp $ zip list [0 .. ]
  where
    cmp (v,i) (w,j) = case compare v w of
                        EQ -> compare j i
                        ne -> ne

缺点是maximummaximumBy太懒了,所以这些可能会构建大量的thunk。为了避免这种情况,要么使用手动递归(就像你做的那样,但是可能需要一些严格的注释)或者使用严格的左侧折叠和严格的累加器类型,元组不是很好,因为{{ 1}}只评估弱头普通形式,即这里最外层的构造函数,因此你在元组组件中构建thunk。

答案 1 :(得分:5)

此解决方案将每个元素与其索引相关联,对列表进行排序,因此最小元素是第一个,将其反转,使最大元素为第一个,获取前n个元素,然后提取索引。

maxn n xs = map snd . take n . reverse . sort $ zip xs [0..]

答案 2 :(得分:2)

嗯,一种简单的方法是使用maximum查找最大的元素,然后使用findIndices查找每个元素。类似的东西:

largestIndices :: Ord a => [a] -> [Int]
largestIndices ls = findIndices (== maximum ls) ls

然而,这并不完美,因为maximum是一个部分功能,并且如果给出一个空列表,将会非常可靠。您可以通过添加[]案例轻松避免这种情况:

largestIndices :: Ord a => [a] -> [Int]
largestIndices [] = []
largestIndices ls = findIndices (== maximum ls) ls

这个答案的真正诀窍是我如何弄明白。我之前甚至都不知道findIndices!但是,GHCi有一个称为:browse的简洁命令。

Prelude> :browse Data.List

列出Data.List导出的每个函数。使用此功能,我只需先搜索maximum,然后搜索index以查看选项。而且,在findIndex之后,有findIndecies,这是完美的。

最后,除非您确实看到代码运行缓慢,否则我不会担心效率。 GHC可以 - 并且确实 - 执行一些非常积极的优化,因为语言是纯粹的,它可以逃脱它。因此,您需要担心性能的唯一时间是 - 在使用-O2编译后 - 您会发现这是一个问题。

编辑:如果你想找到n顶级元素'索引,这里有一个简单的想法:按降序对列表进行排序,获取第一个n个唯一元素,用{{获取它们的索引1}}并从中获取第一个elemIndices索引。我希望这个比较清楚。

以下是我的想法的快速版本:

n