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 new to Ruby.

- 106,649
- 6
- 63
- 100
-
2I think you've got it. What's non-rubylike about that? – Ben Jan 27 '10 at 19:52
-
Ben, I was looking for something like a.max_index. Guess it's not built in. – Cary Swoveland Jan 29 '10 at 18:28
-
1Even if the function you want is not built in, you can still add a `.max_index` member to the `Array` class. Here's an example of extending `String` or `Integer` with a custom member: http://www.hawkee.com/snippet/1260/ – bta Jan 29 '10 at 22:58
7 Answers
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.

- 234,037
- 30
- 302
- 389
-
-
Aaah, got it. each_with_index.max returns an array with the first element being the value and the second being the index of it. Very nice, Chuck. – bergyman Jan 27 '10 at 20:24
-
Although actually still foggy as to why exactly it returns an array like this...heh. – bergyman Jan 27 '10 at 20:26
-
2Chuck, I was aware of this method, but thought Ruby would have a way of returning just the index. (For any others new to Ruby, a.each_with_index.max returns the array [max value, index of max value], so Chuck is just pulling out the second element.) – Cary Swoveland Jan 27 '10 at 20:32
-
29`each_with_index` without a block returns an enumerator that gives the item and its index. We then send `max` to this enumerator, which does the standard `max` algorithm on item-index pairs. `Array.<=>` is implemented so that the first item determines the ordering (unless there's a tie, in which case the second is compared, and so on), so this works basically the same as doing `max` on an array of the values themselves. Then to get the index, we ask for the second item of the result (since we got a series of `[value, index]` pairs from `each_with_index`). – Chuck Jan 27 '10 at 20:32
-
Boy, so is fast! The five comments before mine were posted while I was composing my comment. – Cary Swoveland Jan 27 '10 at 20:34
-
Nice. I was unaware that doing a max on a 2D array like this just compares the value of the first element in each array. – bergyman Jan 27 '10 at 20:37
-
That's a great way of doing it. If using Ruby 1.8.6, `require 'backports'` to get `#each_with_index` – Marc-André Lafortune Jan 27 '10 at 21:07
-
And if you want the max of some function of the array elements, you can use `max_by` in the same way. For example `[0, 1,-1,2].each_with_index.max_by{|x,i| (-x) ** 3}[1]` will equal 2 – Kevin Bullaughey Oct 16 '13 at 01:23
-
8@bergyman It doesn't compare just the first element. It starts comparison with the first element, but it will move on to subsequent elements if the first elements are equal. As such, if there are multiple maximum elements in the array, this solution will give the last one. – Michael Mior Apr 29 '14 at 14:03
-
5I was just drawn back to this question after many moons, and noticed that when the array `a` contains multiple maximum values, `a.index(a.max)` will return the index of the first and `a.each_with_index.max[1]` will return the index of the last, so the choice of which to use may depend on the context. – Cary Swoveland May 18 '16 at 18:55
-
-
@Dave All Array iteration methods will fail on `nil`. Except the ones that deal with `nil`. So you need to get rid of `nil`s. – karatedog Jun 28 '22 at 09:06
In ruby 1.9.2 I can do this;
arr = [4, 23, 56, 7]
arr.rindex(arr.max) #=> 2

- 2,186
- 2
- 23
- 34
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

- 116,827
- 30
- 260
- 317
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.

- 2,913
- 2
- 24
- 22
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]

- 98,345
- 23
- 131
- 206
-
You can use `each_with_object` plus `with_index` and skip the `map(&:last)`; `a.each_with_object([]).with_index { |(e, arr), i| arr << i if e == a.max }`. – Sebastián Palma Jul 06 '20 at 08:09
a = [1, 4 8]
a.inject(a[0]) {|max, item| item > max ? item : max }
At least it's Ruby-like :)

- 19,333
- 6
- 58
- 52
-
Dammit! I was cooking up a solution using inject - you beat me to it! ;) – bergyman Jan 27 '10 at 20:08
-
2Also - original question was to get the index, so this would have to be changed to: a.inject(0) {|index, num| num > a[index] ? a.find_index(num) : index} – bergyman Jan 27 '10 at 20:11
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

- 26,361
- 5
- 21
- 42