如何使用单个字符串键访问散列的嵌套元素?

时间:2011-07-12 22:32:49

标签: ruby hash

我在玩弄Ruby,基本上我已经

@trans = { :links => {
    :quick_notes => "aaaaaaa"
  }
}

我想打电话给

def t
  #...something
end
t('links.quick_notes')

访问

trans[:links][:quick_notes]

我基本上试图实现与使用国际化时相同的功能

I18n.t('something.other.foo') 
我想出了这种方法

 def t(key)
   a=''
   key.to_s.split('.').each{|key|  a+="[:#{key}]" } 
   #now a == "[:links][:quick_notes]"
   #but I cant figure out how can I call it on  @trans variable

 end

 t('links.quick_notes')

有什么想法吗?感谢名单

5 个答案:

答案 0 :(得分:13)

您可以使用inject

到达目的地
def t(key)
    key.to_s.split('.').inject(@trans) { |h, k| h[k.to_sym] }
end

错误检查和“没有这样的条目”检查留作练习。

答案 1 :(得分:1)

对于它的价值,这里有一些显示use of recursion的匿名代码。

def getKeyChain (obj, parts)
  if !obj || parts.size == 0
    # this is the base case
    obj
  else
    # this is the recursive case
    key = parts[0]
    if key.match(/^:/)
      key = key[1..key.size].to_sym
    end
    # each time recursing, pass a new state.
    # in this case, the value for the "key" and the remaining parts
    # that need resolving
    getKeyChain(obj[key], parts[1..parts.size])
  end
end

def getCompoundKey (obj, compound)
  # helper makes it easier to call while not making the
  # recursive function more complex.
  getKeyChain(obj, compound.split("."))
end

h0 = {:x => "hello"}
h1 = {"a" => {:b => "world"}}
puts getCompoundKey(h0, ":x")   # => hello
puts getCompoundKey(h1, "a.:b") # => world

可以做出许多改进......“使用自己的危险”。

快乐的编码。

答案 2 :(得分:1)

如果您正在寻找内插%{variable}的内容,包括数组支持,我一直在使用它:

def interpolate(string, hash)
  string.gsub(/%\{([^\}]*)\}/).each { |match| match[/^%{(.*)}$/, 1].split('.').inject(hash) { |h, k| h[(k.to_s == k.to_i.to_s) ? k.to_i : k.to_sym] } }
end

答案 3 :(得分:1)

由于Ruby 2.3 Hash有dig方法。内置“没有这样的条目”检查:如果缺少任何键,则整个表达式返回nil。用法:

@trans = { :links => {
    :quick_notes => "aaaaaaa"
  }
}

def t (str)
  syms = str.split(".").map(&:to_sym)
  @trans.dig(*syms)
end
p t('links.quick_notes')  # => "aaaaaaa"

答案 4 :(得分:0)

另一个补充 - 如果你有json或包含数组和哈希的哈希 - 可能是这样的:

@trans = { :links => [ {
    :quick_notes => "aaaaaaa"
  },
  {
    :quick_notes => "bbbbbbb"
  } ],
  :page => 1
}

您可以在数组中包含位置测试,您可以执行此类操作。

def t(key)
  key.split('.').inject(@trans) { |h,v| h.send('[]',v.to_i.to_s.eql?(v) ? v.to_i : v) }
end

这将允许您传递像这样的键

t('links.1.quick_notes')

并得到答案'bbbbbb'