How do I use Array#dig and Hash#dig introduced in Ruby 2.3?

Ruby 2.3 introduces a new method on Array and Hash called dig. The examples I've seen in blog posts about the new release are contrived and convoluted:

# Hash#dig
user = {
  user: {
    address: {
      street1: '123 Main street'
    }
  }
}

user.dig(:user, :address, :street1) # => '123 Main street'

# Array#dig
results = [[[1, 2, 3]]]
results.dig(0, 0, 0) # => 1

I'm not using triple-nested flat arrays. What's a realistic example of how this would be useful?

UPDATE

It turns out these methods solve one of the most commonly-asked Ruby questions. The questions below have something like 20 duplicates, all of which are solved by using dig:

How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?

Ruby Style: How to check whether a nested hash element exists

In our case, NoMethodErrors due to nil references are by far the most common errors we see in our production environments.

The new Hash#dig allows you to omit nil checks when accessing nested elements. Since hashes are best used for when the structure of the data is unknown, or volatile, having official support for this makes a lot of sense.

Let's take your example. The following:

user.dig(:user, :address, :street1)

Is not equivalent to:

user[:user][:address][:street1]

In the case where user[:user] or user[:user][:address] is nil, this will result in a runtime error.

Rather, it is equivalent to the following, which is the current idiom:

user[:user] && user[:user][:address] && user[:user][:address][:street1]

Note how it is trivial to pass a list of symbols that was created elsewhere into Hash#dig, whereas it is not very straightforward to recreate the latter construct from such a list. Hash#dig allows you to easily do dynamic access without having to worry about nil references.

Clearly Hash#dig is also a lot shorter.


One important point to take note of is that Hash#dig itself returns nil if any of the keys turn out to be, which can lead to the same class of errors one step down the line, so it can be a good idea to provide a sensible default. (This way of providing an object which always responds to the methods expected is called the Null Object Pattern.)

Again, in your example, an empty string or something like "N/A", depending on what makes sense:

user.dig(:user, :address, :street1) || ""

Ruby 2.3 dig Method, Since Ruby 2.3 launched its new Hash#dig and Array#dig feature, projects using OpenStruct s structures and replace those with hashes. Array#dig() : dig() is a Array class method which extracts the specific element out of the high dimension sequences. Syntax: Array.dig() Parameter: element position. Return: element from a specific location in sequence, returning nil if any intermediate step is nil.

One way would be in conjunction with the splat operator reading from some unknown document model.

some_json = JSON.parse( '{"people": {"me": 6, ... } ...}' )
# => "{"people" => {"me" => 6, ... }, ... }
a_bunch_of_args = response.data[:query]
# => ["people", "me"]
some_json.dig(*a_bunch_of_args)
# => 6

Class: Hash (Ruby 2.3.0), Ruby 2.3 brings Array#dig and Hash#dig. #dig lets you easily traverse nested hashes, arrays, or even a mix of them. It returns nil if any intermediate value is  Hashes have a default value that is returned when accessing keys that do not exist in the hash. If no default is set nil is used. You can set the default value by sending it as an argument to ::new: grades = Hash. new (0) Or by using the default= method: grades = {"Timmy Doe" = > 8} grades. default = 0. Accessing a value in a Hash requires

It's useful for working your way through deeply nested Hashes/Arrays, which might be what you'd get back from an API call, for instance.

In theory it saves a ton of code that would otherwise check at each level whether another level exists, without which you risk constant errors. In practise you still may need a lot of this code as dig will still create errors in some cases (e.g. if anything in the chain is a non-keyed object.)

It is for this reason that your question is actually really valid - dig hasn't seen the usage we might expect. This is commented on here for instance: Why nobody speaks about dig.

To make dig avoid these errors, try the KeyDial gem, which I wrote to wrap around dig and force it to return nil/default if any error crops up.

Ruby 2.3 brings Array#dig and Hash#dig, Introducing `ruby_dig`. It may take us some time to upgrade to Ruby 2.3. But we'd like to be able to start using `dig` right away. The `ruby_dig`  ri Hash.dig = Hash.dig (from ruby core) ----- hsh.dig(key, ) -> object ----- Extracts the nested value specified by the sequence of idx objects by calling dig at each step, returning nil if any intermediate step is nil.

ruby_dig Gem Adds Hash#dig and Array#dig from Ruby 2.3 to , The introduction of the Hash#dig method in Ruby 2.3 completely changed the addresses the value of the :addresses key could be a Hash or an Array . Then if it's a Hash use dig to get the :latitude from the location key. Ruby 2.3 introduit une nouvelle méthode sur Array et Hash appelé dig. Les exemples que j'ai vus dans les billets de blog sur la nouvelle version sont truqués et alambiqués: Les exemples que j'ai vus dans les billets de blog sur la nouvelle version sont truqués et alambiqués:

Introducing Hash#dig_and_collect, a useful extension to the Ruby , It is already 2 years since Ruby 2.3 was released. and conferences, we have heard very little about the Hash#dig and Array#dig methods. And the most important part, should we start using it, if we haven't use it until now? The #dig is basically an elvis operator for hashes and arrays. It’ll retrieve a value from the array/hash, given a set of keys. If no value is found, it’ll return nil. Ruby 2.3 also introduced a safe navigational operator, but I won’t be covering this since Giorgi Mitrev wrote a very good article about it.

Why nobody speaks about dig, Ruby 2.3.0 was released on Christmas. Using Ruby 2.3's dig method and safe navigation operator to navigate nested objects like the about today, allows us to safely access nested data in Hash , Array , or Struct objects. Introducing Hash#dig_and_collect, a useful extension to the Ruby Hash#dig method Posted on November 4, 2016 January 28, 2019 by mottalrd In this blog post I will introduce Hash #dig_and_collect , a simple utility method that is built on top of Hash #dig to help you navigate nested hashes mixed up with arrays.

Comments
  • You just parsed some json is a very realistic example...
  • @JesseSielaff They're not the same. [][][] will fail with an error if any of the keys do not exist. dig will not fail, it will return nil.
  • Firstly, you would get no method error for nil class if you use indexing and something along the way is missing. Secondly, it is easier to make dynamic calls with the dig method.
  • I wish there was a Hash#dig! which would do the equivalent of multiple #fetch's.
  • @Dogweather: You can try submitting a feature request in the issue tracker, and see if someone picks it up. :-)
  • Alternative idioms sometimes seen are arr.fetch(:user, {}).fetch(:address, {})[:street1] and for Rails, arr[:user].try(:[], :address).try(:[], :street1).
  • @Drenmi are there possible instances where it is still preferable to use the old [:a][:b] syntax over dig, given I need to access a chain of keys down a hash?
  • @MartinVerdejo: The only reason I can think of is if you're working on a code base that needs to maintain backwards compatibility with earlier rubies.