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

Arrays 查找数组中第一次出现的最大元素的值和索引,arrays,ruby,Arrays,Ruby,我正在寻找一种方法来查找数组中第一个出现的最大元素的值和索引(在ruby中)。我一直无法找到一种方法来实现这一点,只需要不到2行代码,而且不需要遍历数组 首先,我尝试: example = [1, 100, 2, 100, 3] value, index = example.each_with_index.max 但这给了我最大元素最后一次出现的索引 我目前的做法是: example = [1, 100, 2, 100, 3] value = example.max index = examp

我正在寻找一种方法来查找数组中第一个出现的最大元素的值和索引(在ruby中)。我一直无法找到一种方法来实现这一点,只需要不到2行代码,而且不需要遍历数组

首先,我尝试:

example = [1, 100, 2, 100, 3]
value, index = example.each_with_index.max
但这给了我最大元素最后一次出现的索引

我目前的做法是:

example = [1, 100, 2, 100, 3]
value = example.max
index = example.find_index(value)
这是可行的,但是如果最大元素的第一次和最后一次出现是数组的最后两个元素,那么我当前的代码几乎必须遍历整个数组两次


我对性能比对代码大小更感兴趣,但如果有一个非浪费性的单行解决方案,那就太好了

这里是一个单通道解决方案,但如果它比OP的双通道解决方案快,我会感到惊讶,因为and都是用C实现的,并且都是针对阵列进行优化的(与它们的
可枚举的
对应项相反)

当您尝试使用_index.max示例时,首先计算

enum = example.each_with_index
  #=> #<Enumerator: [1, 100, 2, 100, 3]:each_with_index>
当发送到
enum
时,它对
enum
生成的元素进行排序,从大到小,如下所示

[[100, 3], [100, 1], [3, 4], [2, 2], [1, 0]]
订购的原因在文件的第三段中解释

这就是为什么你获得了

enum.max
  #=> [100, 3]
相比之下,我一直在搜索中的最大值

a = [[1, 0], [100, -1], [2, -2], [100, -3], [3, -4]]
那是

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

因此,返回
[100,1]

这里是一个单通解决方案,但如果它比OP的双通解决方案快,我会感到惊讶,因为和都是用C实现的,并且都是针对数组优化的(与它们的
可枚举的
对应项相反)

当您尝试使用_index.max
示例时,首先计算

enum = example.each_with_index
  #=> #<Enumerator: [1, 100, 2, 100, 3]:each_with_index>
当发送到
enum
时,它对
enum
生成的元素进行排序,从大到小,如下所示

[[100, 3], [100, 1], [3, 4], [2, 2], [1, 0]]
订购的原因在文件的第三段中解释

这就是为什么你获得了

enum.max
  #=> [100, 3]
相比之下,我一直在搜索中的最大值

a = [[1, 0], [100, -1], [2, -2], [100, -3], [3, -4]]
那是

a.max
  #=> [100, -1]
因此返回
[100,1]

我对表演更感兴趣

你真的应该测量一下。您自己的解决方案比Cary的解决方案快约75倍(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.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倍


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

我对表演更感兴趣

你真的应该测量一下。您自己的解决方案比Cary的解决方案快约75倍(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.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倍


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


为什么
max
max\u by
之间有差异?@SagarPandya你是说有什么区别吗?@sawa我的意思是,为什么
max
返回最后一次出现,而
max\u by(&:first)
返回第一次出现。@SagarPandya因为,对于
max
,当第一个元素相同时,比较取决于第二个元素。这就是数组比较的工作原理
max_by(&:first)
表示只考虑第一个元素。@StefanPochmann,我把这个问题理解为要求一个单通解决方案,而不是比OP的双通解决方案快的单通解决方案。我做了一个编辑来澄清这一点。编辑反映了我当时的想法。我对你的基准测试结果一点也不惊讶。为什么
max
max_by
之间存在差异?@SagarPandya你是说有什么区别吗?@sawa我的意思是,
max
返回最后一次出现,而
max_by(&:first)
返回第一次。@SagarPandya因为,
max
返回第一次出现,当第一个元素相同时,比较取决于第二个元素。这就是数组比较的工作原理
max_by(&:first)
表示只考虑第一个元素。@StefanPochmann,我把这个问题理解为要求一个单通解决方案,而不是比OP的双通解决方案快的单通解决方案。我做了一个编辑来澄清这一点。编辑反映了我当时的想法。我对你的基准测试结果一点也不惊讶。这是一个全面的基准测试的好观点。我确实将运行时间与我正在处理的数据进行了比较,我没有发现我认为有显著差异的地方(我假设我有时看到的非常微小的差异会被更大数据集的更高效率所抵消)。但这在你的基准中是显而易见的,而且