Может кто-нибудь объяснить мне, в чем разница между Hash # dig и Hash # fetch - PullRequest
0 голосов
/ 30 марта 2019

Я пытаюсь получить вложенное значение в хэше. Я пытался использовать Hash#fetch и Hash#dig, но я не понимаю, как они должны быть объединены.

Мой хэш выглядит следующим образом.

response = {
   "results":[
      {
         "type":"product_group",
         "value":{
            "destination":"Rome"
         }
      },
      {
         "type":"product_group",
         "value":{
            "destination":"Paris"
         }
      },
      {
         "type":"product_group",
         "value":{
            "destination":"Madrid"
         }
      }
   ]
}

Я пробовал следующее

response.dig(:results)[0].dig(:value).dig(:destination) #=> nil
response.dig(:results)[0].dig(:value).fetch('destination') #=> Rome

Желаемое возвращаемое значение: "Rome". Второе выражение работает, но я хотел бы знать, можно ли его упростить.

Я использую Ruby v2.5 и Rails v5.2.1.1.

Ответы [ 2 ]

4 голосов
/ 30 марта 2019

Hash # fetch здесь не имеет значения. Это потому, что fetch совпадает с Hash # [] , когда, как здесь, fetch имеет только один аргумент. Итак, давайте сосредоточимся на dig.

В Ruby v2.3 было введено семейство из трех dig методов: Hash # dig , Array # dig и OpenStruct # dig . Интересная вещь об этих методах состоит в том, что они вызывают друг друга (но это не объяснено в документах, даже в примерах). В вашей задаче мы можем написать:

response.dig(:results, 0, :value, :destination)
  #=> "Rome" 

response - хеш, поэтому Hash#dig оценивает response[:results]. Если его значение равно nil, выражение возвращает nil. Например,

response.dig(:cat, 0, :value, :destination)
  #=> nil

На самом деле response[:results] - это массив:

arr = response[:results]
  #=> [{:type=>"product_group", :value=>{:destination=>"Rome"}},
  #    {:type=>"product_group", :value=>{:destination=>"Paris"}},
  #    {:type=>"product_group", :value=>{:destination=>"Madrid"}}]

Hash#dig поэтому вызывает Array#dig на arr, получая хеш

h = arr.dig(0)
  #=> {:type=>"product_group", :value=>{:destination=>"Rome"}} 

Array#dig затем вызывает Hash#dig на h:

g = h.dig(:value)
  #=> {:destination=>"Rome"}

Наконец, g является хешем, Hash#dig вызывает Hash#dig на g:

g.dig(:destination)
  #=> "Rome"
1 голос
/ 30 марта 2019

Hash#dig

dig(key, ...) → object

Извлекает вложенное значение, указанное в последовательности ключевых объектов, вызывая dig на каждом шаге,возвращает nil, если какой-либо промежуточный шаг равен nil.

Hash#fetch

fetch(key [, default] ) → obj

fetch(key) {| key | block } → obj

Возвращает значение из хэша для данного ключа.Если ключ не может быть найден, есть несколько вариантов: без других аргументов это вызовет исключение KeyError;если задано default , то оно будет возвращено;если указан необязательный блок кода, он будет запущен и его результат будет возвращен.

Вот как выглядит разница в вашем примере:

response = {
  "results": [
    {
      "type": 'product_group',
      "value": {
        "destination": 'Rome'
      }
    },
    {
      "type": 'product_group',
      "value": {
        "destination": 'Paris'
      }
    },
    {
      "type": 'product_group',
      "value": {
        "destination": 'Madrid'
      }
    }
  ]
}

response[:results].first.dig(:value, :destination) #=> "Rome"
response[:results].first.fetch(:value).fetch(:destination) #=> "Rome"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...