通过Ruby中的路径替换和访问嵌套的hash/json中的值 [英] Replace and access values in nested hash/json by path in Ruby
问题描述
征求意见,您认为最好的和简单的解决方案是使用ruby通过路径ir变量替换和访问嵌套哈希或json中的值吗?
Asking for a advice what would be in your opinion best and simple solution to replace and access values in nested hash or json by path ir variable using ruby?
例如,假设我有具有这种结构的json或哈希:
For example imagine I have json or hash with this kind of structure:
{
"name":"John",
"address":{
"street":"street 1",
"country":"country1"
},
"phone_numbers":[
{
"type":"mobile",
"number":"234234"
},
{
"type":"fixed",
"number":"2342323423"
}
]
}
我想按路径访问或更改固定的手机号码,该路径可以在这样的变量中指定:"phone_numbers/1/number"
(在这种情况下,分隔符无关紧要)
And I would like to access or change fixed mobile number by path which could be specified in variable like this: "phone_numbers/1/number"
(separator does not matter in this case)
此解决方案对于从json/hash检索值以及有时通过指定其路径来替换变量是必需的.找到了一些可以通过键找到值的解决方案,但是该解决方案无法正常工作,因为存在一些哈希/json,其中多个地方的键名相同.
This solution is necessary to retrieve values from json/hash and sometimes replace variables by specifying path to it. Found some solutions which can find value by key, but this solution wouldn't work as there is some hashes/json where key name is same in multiple places.
我看到了这个: https://github.com/chengguangnan/vine ,但是当有效负载是这样时,它不起作用,因为在这种情况下,它不是散列:
I saw this one: https://github.com/chengguangnan/vine , but it does not work when payload is like this as it is not kinda hash in this case:
[
{
"value":"test1"
},
{
"value":"test2"
}
]
希望您有一些解决此问题的好主意.
Hope you have some great ideas how to solve this problem.
谢谢!
因此,我尝试使用此数据在下面的代码中:
So I tried code below with this data:
x = JSON.parse('[
{
"value":"test1"
},
{
"value":"test2"
}
]')
y = JSON.parse('{
"name":"John",
"address":{
"street":"street 1",
"country":"country1"
},
"phone_numbers":[
{
"type":"mobile",
"number":"234234"
},
{
"type":"fixed",
"number":"2342323423"
}
]
}')
p x
p y.to_h
p x.get_at_path("0/value")
p y.get_at_path("name")
得到了:
[{"value"=>"test1"}, {"value"=>"test2"}]
{"name"=>"John", "address"=>{"street"=>"street 1", "country"=>"country1"}, "phone_numbers"=>[{"type"=>"mobile", "number"=>"234234"}, {"type"=>"fixed", "number"=>"2342323423"}]}
hash_new.rb:91:in `<main>': undefined method `get_at_path' for [{"value"=>"test1"}, {"value"=>"test2"}]:Array (NoMethodError)
对于y.get_at_path("name")
,得到nil
推荐答案
您可以使用 Hash.dig
来获取子值,它将继续在每个步骤的结果上调用dig
,直到到达末尾为止,然后
You can make use of Hash.dig
to get the sub-values, it'll keep calling dig
on the result of each step until it reaches the end, and Array
has dig
as well, so when you reach that array things will keep working:
# you said the separator wasn't important, so it can be changed up here
SEPERATOR = '/'.freeze
class Hash
def get_at_path(path)
dig(*steps_from(path))
end
def replace_at_path(path, new_value)
*steps, leaf = steps_from path
# steps is empty in the "name" example, in that case, we are operating on
# the root (self) hash, not a subhash
hash = steps.empty? ? self : dig(*steps)
# note that `hash` here doesn't _have_ to be a Hash, but it needs to
# respond to `[]=`
hash[leaf] = new_value
end
private
# the example hash uses symbols as the keys, so we'll convert each step in
# the path to symbols. If a step doesn't contain a non-digit character,
# we'll convert it to an integer to be treated as the index into an array
def steps_from path
path.split(SEPERATOR).map do |step|
if step.match?(/\D/)
step.to_sym
else
step.to_i
end
end
end
end
,然后可以将其原样使用(hash
包含您的示例输入):
and then it can be used as such (hash
contains your sample input):
p hash.get_at_path("phone_numbers/1/number") # => "2342323423"
p hash.get_at_path("phone_numbers/0/type") # => "mobile"
p hash.get_at_path("name") # => "John"
p hash.get_at_path("address/street") # => "street 1"
hash.replace_at_path("phone_numbers/1/number", "123-123-1234")
hash.replace_at_path("phone_numbers/0/type", "cell phone")
hash.replace_at_path("name", "John Doe")
hash.replace_at_path("address/street", "123 Street 1")
p hash.get_at_path("phone_numbers/1/number") # => "123-123-1234"
p hash.get_at_path("phone_numbers/0/type") # => "cell phone"
p hash.get_at_path("name") # => "John Doe"
p hash.get_at_path("address/street") # => "123 Street 1"
p hash
# => {:name=>"John Doe",
# :address=>{:street=>"123 Street 1", :country=>"country1"},
# :phone_numbers=>[{:type=>"cell phone", :number=>"234234"},
# {:type=>"fixed", :number=>"123-123-1234"}]}
这篇关于通过Ruby中的路径替换和访问嵌套的hash/json中的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!