[英]how to make a deep_slice in a hash on ruby
I was looking around for a clean way to do this and I found some workarounds but did not find anything like the slice (some people recommended to use a gem but I think is not needed for this operations, pls correct me if I am wrong), so I found myself with a hash that contains a bunch of hashes and I wanted a way to perform the Slice operation over this hash and get also the key/value pairs from nested hashes, so the question:我一直在寻找一种干净的方法来做到这一点,我找到了一些解决方法,但没有找到像切片这样的东西(有些人建议使用 gem,但我认为这个操作不需要,如果我错了请纠正我) ,所以我发现自己有一个包含一堆哈希的 hash,我想要一种方法来对这个 hash 执行切片操作,并从嵌套哈希中获取键/值对,所以问题是:
Is there something like deep_slice in ruby? ruby 中是否有类似 deep_slice 的东西?
Example:例子:
input: a = {b: 45, c: {d: 55, e: { f: 12}}, g: {z: 90}}, keys = [:b, :f, :z]
expected output: {:b=>45, :f=>12, :z=>90}
Thx in advance!提前谢谢!
After looking around for a while I decided to implement this myself, this is how I fix it:在环顾了一段时间后,我决定自己实现这个,这就是我修复它的方法:
a = {b: 45, c: {d: 55, e: { f: 12}}, g: {z: 90}}
keys = [:b, :f, :z]
def custom_deep_slice(a:, keys:)
result = a.slice(*keys)
a.keys.each do |k|
if a[k].class == Hash
result.merge! custom_deep_slice(a: a[k], keys: keys)
end
end
result
end
c_deep_slice = custom_deep_slice(a: a, keys: keys)
p c_deep_slice
The code above is a classic DFS , which takes advantage of the merge!上面的代码是一个经典的DFS ,它利用了合并! provided by the hash class.
由 hash class 提供。
require 'set'
def recurse(h, keys)
h.each_with_object([]) do |(k,v),arr|
if keys.include?(k)
arr << [k,v]
elsif v.is_a?(Hash)
arr.concat(recurse(v,keys))
end
end
end
hash = { b: 45, c: { d: 55, e: { f: 12 } }, g: { b: 21, z: 90 } }
keys = [:b, :f, :z]
arr = recurse(hash, keys.to_set)
#=> [[:b, 45], [:f, 12], [:b, 21], [:z, 90]]
Notice that hash
differs slightly from the example hash given in the question.请注意,
hash
与问题中给出的示例 hash 略有不同。 I added a second nested key :b
to illustrate the problem of returning a hash rather than an array of key-value pairs.我添加了第二个嵌套键
:b
来说明返回 hash 而不是键值对数组的问题。 Were we to convert arr
to a hash the pair [:b, 45]
would be discarded:如果我们将
arr
转换为 hash 对[:b, 45]
将被丢弃:
arr.to_h
#=> {:b=>21, :f=>12, :z=>90}
If desired, however, one could write:但是,如果需要,可以写:
arr.each_with_object({}) { |(k,v),h| (h[k] ||= []) << v }
#=> {:b=>[45, 21], :f=>[12], :z=>[90]}
I converted keys
from an array to a set merely to speed lookups ( keys.include?(k)
).我将
keys
从数组转换为集合只是为了加快查找速度( keys.include?(k)
)。
A slightly modified approach could be used if the hash contained nested arrays of hashes as well as nested hashes.如果 hash 包含嵌套的散列 arrays 以及嵌套的散列,则可以使用稍微修改的方法。
My version我的版本
maybe it should help也许它应该有帮助
def deep_slice( obj, *args )
deep_arg = {}
slice_args = []
args.each do |arg|
if arg.is_a? Hash
arg.each do |hash|
key, value = hash
if obj[key].is_a? Hash
deep_arg[key] = deep_slice( obj[key], *value )
elsif obj[key].is_a? Array
deep_arg[key] = obj[key].map{ |arr_el| deep_slice( arr_el, *value) }
end
end
elsif arg.is_a? Symbol
slice_args << arg
end
end
obj.slice(*slice_args).merge(deep_arg)
end
Object to slice Object 切片
obj = {
"id": 135,
"kind": "transfer",
"customer": {
"id": 1,
"name": "Admin",
},
"array": [
{
"id": 123,
"name": "TEST",
"more_deep": {
"prop": "first",
"prop2": "second"
}
},
{
"id": 222,
"name": "2222"
}
]
}
Schema to slice要切片的架构
deep_slice(
obj,
:id,
customer: [
:name
],
array: [
:name,
more_deep: [
:prop2
]
]
)
Result结果
{
:id=>135,
:customer=>{
:name=>"Admin"
},
:array=>[
{
:name=>"TEST",
:more_deep=>{
:prop2=>"second"
}
},
{
:name=>"2222"
}
]
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.