查找数组中最大元素的第一个出现的值和索引

时间:2017-12-07 02:56:49

标签: arrays ruby

我正在寻找一种方法来查找数组中最大元素 first 出现的值和索引(在ruby中)。我没有找到一种方法来实现这一目标,只需少于2行代码,并且没有超出我想要的数量。

首先我尝试了:

example = [1, 100, 2, 100, 3]
value, index = example.each_with_index.max

但是这给了我最大元素的 last 出现的索引。

我目前的做法是:

example = [1, 100, 2, 100, 3]
value = example.max
index = example.find_index(value)

哪个有效,但是如果最大元素的第一个和最后一个出现是数组的最后两个元素,那么我当前的代码必须遍历整个数组两次。

我对性能比对代码大小更感兴趣,但是如果有一个非浪费的单行解决方案会很棒!

2 个答案:

答案 0 :(得分:3)

这是一次性解决方案,但如果它比OP的两遍解决方案更快,我会感到惊讶,因为Array#maxArray#find_index都在C中实现并且针对数组(与Enumerable对应数据相对)。

 value, index = example.each_with_index.max_by { |n,i| [n,-i] }
  #=> [100, 1]

当您尝试example.each_with_index.max时,您首先计算了

enum = example.each_with_index
  #=> #<Enumerator: [1, 100, 2, 100, 3]:each_with_index>

我们可以将此枚举器转换为数组,以查看它将生成哪些元素。

enum.to_a
  #=> [[1, 0], [100, 1], [2, 2], [100, 3], [3, 4]]

Array#max发送到enum时,它将enum生成的元素排序为最大到最小,如下所示。

[[100, 3], [100, 1], [3, 4], [2, 2], [1, 0]]

此排序的原因在Array#<=>的文档的第三段中进行了解释。

这就是你获得

的原因
enum.max
  #=> [100, 3]

相比之下,我Enumerable#max_by

中搜索最大值
a = [[1, 0], [100, -1], [2, -2], [100, -3], [3, -4]]

a.max
  #=> [100, -1]

所以返回[100, 1]

答案 1 :(得分:1)

  

我对表现更感兴趣

你真的应该衡量一下。你自己的解决方案比Cary的解决方案<强>快75倍(谁也应该测量)。

              user     system      total        real
Yours     0.484000   0.000000   0.484000 (  0.485868)
Cary's   36.094000   0.000000  36.094000 ( 36.412679)

是的,您的解决方案遍历数组两次。但这是两次快速遍历。 Cary只有一次遍历,但它是。他为每个元素做了更多的工作,一个枚举器参与其中,并且他在Ruby代码中部分地执行它。

我的基准代码:

require 'benchmark'

example = (1..10**8).to_a
Benchmark.bm(7) do |x|
  x.report("Yours") {
    value = example.max
    index = example.index(value)
  }
  x.report("Cary's") {
    value, index = example.each_with_index.max_by { |n,i| [n,-i] }
  }
end

我已将您的example.find_index更改为example.index。一样。只是简短的名字。

最快的单程解决方案(如果你出于某种原因坚持一个),我想出的是:

value, index = example[0], 0
i = 0
example.each do |v|
  if v > value
    value = v
    index = i
  end
  i += 1
end

大约需要4.8秒,所以比Cary快7.5倍,但仍然比你的慢10倍。

底线:使用您自己的解决方案。你甚至可以把它做成一个简短的单行(但我不会):

index = example.index(value = example.max)