0
h = {
  users: {
    u_548912: {
      name: "John",
      age: 30
    },
    u_598715: {
      name: "Doe",
      age: 30
    }
  }
}

Given a hash like above, say I want to get user John, I can do

h[:users].values.first[:name]    # => "John"

In Ruby 2.3 use Hash#dig can do the same thing:

h.dig(:users, :u_548912, :name)  # => "John"

But given that the u_548912 is just a random number(no way to know it before hand), is there a way to get the information still using Hash#dig?

sbs
  • 4,102
  • 5
  • 40
  • 54

1 Answers1

2

You can, of course, pass an expression as an argument to #dig:

h.dig(:users, h.dig(:users)&.keys&.first, :name)
#=> John

Extract the key if you want more legibility, at the cost of lines of code:

first_user_id = h.dig(:users)&.keys&.first
h.dig(:users, first_user_id, :name)
#=> John

Another option would be to chain your #dig method calls. This is shorter, but a bit less legible.

h.dig(:users)&.values&.dig(0, :name)
#=> John

I'm afraid there is no "neater" way of doing this while still having safe navigation.

Drenmi
  • 8,492
  • 4
  • 42
  • 51
  • why not just `h[:users].values.first[:name]` – DiegoSalazar Jan 05 '16 at 18:42
  • If `h[:users]` does not respond to `#values`, or `h[:users].values` does not respond to `#first`, or `h[:users].values.first` does not respond to `#[]`, your application blows up. You get the idea. :-) Both `#dig` and the safe navigation (lonely) operator were implemented in 2.3 to avoid this. – Drenmi Jan 05 '16 at 18:45
  • 2
    legit, but ugly af :) – Rustam Gasanov Jan 05 '16 at 19:11