Рубиновый вложенный хеш из массива - PullRequest
1 голос
/ 06 марта 2019

Мне нужно преобразовать этот массив:

[:a, :b, :c, :d, :e]

В этот хэш:

{:a=>{:b=>{:c=>{:d=>:e}}}}

К сожалению, мне не хватает рекурсивной доли мозга.Я нашел BottomlessHash

# http://firedev.com/posts/2015/bottomless-ruby-hash/
class BottomlessHash < Hash
  def initialize
    super &-> h, k { h[k] = self.class.new }
  end
end

Пока я изо всех сил пытаюсь понять " удар кренделя ", он добьется цели, если вы напишите его явно,

bhash = BottomlessHash.new
bhash[:a][:b][:c][:d] = :e 
bhash # => {:a=>{:b=>{:c=>{:d=>:e}}}} 

Однако я не могу найти способ программной передачи произвольных значений.

store не работает и send("[:a][:b][:c][:d]=", :e)

Ответы [ 4 ]

3 голосов
/ 06 марта 2019

То, что делает send, вызывает метод , всего один, с нулем или более аргументов.Он не может вызывать несколько методов одновременно.Ваш пример здесь:

send("[:a][:b][:c][:d]=", :e)

Это пытается вызвать метод с именем, буквально, [:a][:b][:b][:d]=, который не существует, поэтому send завершается ошибкой.

Теперь этот битФактический код Ruby:

x[:a][:b][:c][:d] = :e

. Ruby интерпретируется как:

x.send(:[], :a).send(:[], :b).send(:[], :c).send(:[]=, :d, :e)

Это очень длинный и уродливый способ сделать то, что сделал исходный код.Ключевым моментом здесь является то, что каждая [...] часть представляет вызов метода, который возвращает что-то, и затем следующая часть сравнивается с этим, или приковывается к .

Теперь для исходной части этоpretzel-stab:

super &-> h, k { h[k] = self.class.new }

& означает «пройти через этот Proc в качестве аргумента блока», как в случае с методом с подписью:

initialize(&block)

Где &block представляет блок, если он указан, этому методу, например:

Hash.new { |h,k| h[k] = { } }

В более базовой реализации.

Часть -> h, k { ... } традиционно записывается как:

lambda { |h, k| ... }

Где это, вероятно, более узнаваемо.

2 голосов
/ 07 марта 2019
[:a, :b, :c, :d, :e].reverse_each.inject{|h, k| {k => h}}
# => {:a=>{:b=>{:c=>{:d=>:e}}}}
1 голос
/ 06 марта 2019
array = [*:a..:e]
array[0..-2].reverse.reduce(array[-1]) { |b, a| { a => b } }
#  {:a=>{:b=>{:c=>{:d=>:e}}}}
1 голос
/ 06 марта 2019
items = [:a, :b, :c, :d, :e]

# Iterative version
def hashify(items)
  items = items.dup

  result = items.pop
  result = {items.pop => result} until items.empty?
  result
end

hashify(items) # => {:a=>{:b=>{:c=>{:d=>:e}}}}

# Recursive version
def hashify(items)
  return items.last if items.size < 2

  *head, penultimate, last = items
  hashify(head + [{penultimate => last}])
end

hashify(items) # => {:a=>{:b=>{:c=>{:d=>:e}}}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...