Ruby hash.dig с использованием массива в качестве аргумента?

#ruby #hash

#массивы #ruby #хэш #splat

Вопрос:

У меня есть вложенный хэш данных

 foo => {
  'user' => { 
    'address' => {
      'street' => '1234'
    }
  }
}
  

Я могу получить доступ к значениям, используя Hash.dig

 foo.dig('user', 'address', 'street')
1234
  

Как бы вы использовали hash.dig, когда значения являются переменными и определены в массиве?

 query=["users", "address", "street"]
  
foo.dig(query) # <= doesn't work  
foo.dig(query.to_s) # <= doesn't work  
  

Глядя на документы ruby, Hash.dig, похоже, принимает несколько параметров, но не принимает массив

https://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig

Комментарии:

1. Имейте в виду, что массив является допустимым хэш-ключом, поэтому вызов Hash#dig с аргументом массива является допустимым и разумным.

Ответ №1:

Вы можете сделать это с помощью оператора splat, чтобы разделить массив на список аргументов таким образом:

 foo.dig(*query)
  

Комментарии:

1. Кстати, имя — «оператор splat»

Ответ №2:

Я бы использовал ответ Алекса для типичного варианта использования, но поскольку он разбивает массив на аргументы, накладных расходов больше, и при больших входных данных я получаю ошибку stack too deep. Это не ошибка, с которой вы столкнетесь, если у вас нет огромного списка, но, возможно, стоит понять в любом случае.

 # one million keys
# note that none of these are actually present in the hash
query = 1.upto(1_000_000).to_a

foo.dig(*query)
# => StackTooDeep

query.reduce(foo) do |memo, key|
  memoamp;.dig(key) || break
end
# => returns nil instantly
  

Комментарии:

1. Если у вас структура глубиной в миллион уровней, у вас, вероятно, есть другие проблемы.

2. Да, согласен, но я думаю, что урок здесь не столько о dig, сколько о том, что разделение массивов на аргументы не работает с большими массивами.

3. @maxpleaner Спасибо за ответ! Это заставило меня задуматься о других вариантах использования reduce paradigm, помимо использования, обсуждаемого в этом посте (для обхода «splat» для больших массивов). И нет, я не воспринял этот игрушечный пример как совет по созданию монстров глубиной в миллион уровней. Наоборот! Я просто подозреваю, что в один прекрасный день мне, возможно, придется отлаживать код, в котором кто-то случайно создал такую вещь. Может быть, даже несколько вещей, если бы они знали о циклах. 🙂

4. Хах, приятно слышать. Да, я чувствую, что улучшение перечислимых методов стало первым способом улучшения моего кода за последние несколько лет.