28

As of Ruby 1.9, hashes retain insertion order which is very cool. I want to know the best way to access the last key–value pair.

I've written some code which does this:

hash.values.last

This works and is very easy to comprehend, but perhaps it's possible to access the last value directly, rather that via an intermediary (the array of values). Is it?

davidchambers
  • 23,918
  • 16
  • 76
  • 105

4 Answers4

30

Hash have a "first" method, but that return the first pair in array mode, for last, you can try:

my_hash.to_a.last

this return last pair in array mode like "first method"

29

One more alternative that I'm using myself:

hash[hash.keys.last]

which works out better when you want to directly assign a value onto the last element of the hash:

2.4.1 :001 > hash = {foo: 'bar'}
 => {:foo=>"bar"} 
2.4.1 :002 > hash[hash.keys.last] = 'baz'
 => "baz" 
2.4.1 :003 > hash.values.last = 'bar'
NoMethodError: undefined method `last=' for ["baz"]:Array
Did you mean?  last
    from (irb):3
    from /home/schuylr/.rvm/rubies/ruby-2.4.1/bin/irb:11:in `<main>'
sjagr
  • 15,983
  • 5
  • 40
  • 67
14

Nothing built in, no. But you could monkey-patch one if you were so inclined (not usually recommended, of course):

class Hash
  def last_value
    values.last
  end
end

And then:

hash.last_value
Ben Lee
  • 52,489
  • 13
  • 125
  • 145
3

I just did this for a very large hash:

hash.reverse_each.with_index do |(_, value), index|
  break value if (index == 0)
end
SHS
  • 7,651
  • 3
  • 18
  • 28
  • This is about 2-3 times faster: `v = hash.each_value.reverse_each.next rescue StopIteration`. Still 2-3 times slower than `hash.values.last` for 100M entries, though. – jaynetics Jun 08 '18 at 21:19
  • 1
    Looking up why this is so slow, I found that `#reverse_each` only makes sense on Arrays. Hash and other Enumerables first [create an intermediate Array](https://github.com/ruby/ruby/blob/trunk/enum.c#L2307) when `#reverse_each` is called, in the case of Hash one with all keys and values. – jaynetics Jun 09 '18 at 17:57