In Ruby, what is the cleanest way of obtaining the index of the largest value in an array?
If a
is the array, I want a.index(a.max)
, but something more Ruby-like. It should be obvious, but I'm having trouble finding the answer at so and elsewhere. Obviously, I am n开发者_如何学JAVAew to Ruby.
For Ruby 1.8.7 or above:
a.each_with_index.max[1]
It does one iteration. Not entirely the most semantic thing ever, but if you find yourself doing this a lot, I would wrap it in an index_of_max
method anyway.
In ruby 1.9.2 I can do this;
arr = [4, 23, 56, 7]
arr.rindex(arr.max) #=> 2
Here is what I am thinking to answer this question :
a = (1..12).to_a.shuffle
# => [8, 11, 9, 4, 10, 7, 3, 6, 5, 12, 1, 2]
a.each_index.max_by { |i| a[i] }
# => 9
Just wanted to note a behavioral and performance difference for some of the solutions here. The "tie breaking" behavior of duplicate max elements:
a = [3,1,2,3]
a.each_with_index.max[1]
# => 3
a.index(a.max)
# => 0
Out of curiosity I ran them both in Benchmark.bm
(for the a
above):
user system total real
each_with_index.max 0.000000 0.000000 0.000000 ( 0.000011)
index.max 0.000000 0.000000 0.000000 ( 0.000003)
Then I generated a new a
with Array.new(10_000_000) { Random.rand }
and reran the test:
user system total real
each_with_index.max
2.790000 0.000000 2.790000 ( 2.792399)
index.max 0.470000 0.000000 0.470000 ( 0.467348)
This makes me think unless you specifically need to choose the higher index max, a.index(a.max)
is the better choice.
Here is a way to get all the index values of the max values if more than one.
Given:
> a
=> [1, 2, 3, 4, 5, 6, 7, 9, 9, 2, 3]
You can find the index of all the max values (or any given value) by:
> a.each_with_index.select {|e, i| e==a.max}.map &:last
=> [7, 8]
a = [1, 4 8]
a.inject(a[0]) {|max, item| item > max ? item : max }
At least it's Ruby-like :)
Using #each_with_index
and #each_with_object
. Only one pass required.
def index_of_first_max(e)
e.each_with_index.each_with_object({:max => nil, :idx => nil}) { |x, m|
x, i = x
if m[:max].nil? then m[:max] = x
elsif m[:max] < x then m[:max] = x; m[:idx] = i
end
}[:idx]
end
Or combining #each_with_index
with #inject
:
def index_of_first_max(e)
e.each_with_index.inject([nil, 0]) { |m, x|
x, i = x
m, mi = m
if m.nil? || m < x then [x, i]
else [m, mi]
end
}.last
end
精彩评论