Reputation: 71
I've got a really confusing question that I can't seem to figure out.
Say I have this hash
hash = {
"lock_version"=>1,
"exhibition_quality"=>false,
"within"=>["FID6", "S5"],
"representation_file"=>{
"lock_version"=>0,
"created_by"=>"admin",
"within"=>["FID6", "S5"]
}
}
How can I delete from "within"=>["FID6", "S5"]
a value with the pattern FID<Number>
(in this example FID6
)?
I've thought about it a bit and used the .delete, .reject! the within but I realised this was deleting the whole key value pair which is not what I want. Thanks a lot for any help that can put me on the right path.
Upvotes: 0
Views: 490
Reputation: 21110
You could use a method or proc/lambda to achieve the result. This solutions splits up the logic in two parts. Removing the actual FID<Number>
string from the array and recursively calling the former on the correct key.
remove_fid = ->(array) { array.grep_v(/\AFID\d+\z/) }
remove_nested_fid = lambda do |hash|
hash.merge(
hash.slice('within').transform_values(&remove_fid),
hash.slice('representation_file').transform_values(&remove_nested_fid)
)
end
pp hash.then(&remove_nested_fid) # or remove_nested_fid.call(hash)
# {"lock_version"=>1,
# "exhibition_quality"=>false,
# "within"=>["S5"],
# "representation_file"=>
# {"lock_version"=>0, "created_by"=>"admin", "within"=>["S5"]}}
grep_v
removes all strings from the array that do not match the given regex.
slice
creates a new hash only containing the given keys. If a key is missing it will not be present in the resulting hash.
transform_values
transforms the values of a hash into a new value (similar to map
for Array), returning a hash.
merge
creates a new hash, merging the hashes together.
This solution does not mutate the original hash
structure.
Upvotes: 1
Reputation: 9397
You're going to need to recurse over the Hash and, in cases where the value is a Hash, process it using the same function, repeatedly. This can be problematic in Ruby -- which doesn't handle recursion very well -- if the depth of the tree is too deep, but it's the most natural way to express this type of issue.
def filter_fids(h)
h.each_pair do |k, v|
if v.is_a? Hash
filter_fids v
elsif k == "within"
v.reject! { |x| x.start_with? "FID" }
end
end
end
This will mutate the original data structure in place.
Upvotes: 0