1

I have a hash which is say,

hash = {"lock_version"=>4, "exhibition_quality"=>false, "within"=>["FID6", "S2"], "repository"=> {"ref"=>"/repositories/2", "repository"=>{"ref"=>"/repositories/2", "within"=>["FID6", "S2"] } } 

This hash is been passed through another function. How can I delete from "within"=>["FID6", "S5"] a value with the pattern FID (in this example FID6) without mutating the original hash ash well? This is just a shortened version of the hash but there are other instances where the hash is super long and "within" key value pair appears multiple times. Note: This program is using ruby 2.4

I have been asked to clarify how this question is different from a previous question I asked so this is a little bit of more clarification because I've done more work on it since. This specific key value pair "within"=>["FID6", "S2"], is now appearing deeply nested (the entire hash is about 2 pages long, hence why I didn't copy and paste it). I can't split the hash where the "repository" is because it appears nested in other key values. What I'm asking now is just is there a way to match that within key value no matter now deep it. Thanks everyone for the suggestions.

4
  • 1
    You should consider highlighting the ways that this question differs from your suspiciously similar question from a few days back. Commented Jun 29, 2020 at 1:54
  • Hi yes I will do that. Thanks for the suggestion @SimpleLime Commented Jun 29, 2020 at 1:59
  • ["FID6", "S2"] is the value of hash's key "within" and of the key "within" that is a key of a hash that is the value of the key "repository" that is a key of hash. Is that the only place the key "within" can be found, or, for example, might the key "repository" have a different name or could there be more levels of nested hashes? Note you wrote ["FID6", "S5"] where I expect you meant ["FID6", "S2"]. Commented Jun 29, 2020 at 3:22
  • Does this answer your question? How would I remove multiple nested values from a hash Commented Jun 29, 2020 at 4:11

2 Answers 2

1

Code

def defidder(h) h.each_with_object({}) do |(k,v),h| h[k] = case v when Array v.reject { |s| s.match?(/\AFID\d+\z/) } if k == "within" when Hash defidder(v) else v end end end 

Example

I've added another layer of hash nesting to the example given in the question:

hash = { "lock_version"=>4, "exhibition_quality"=>false, "within"=>["FID6", "S2"], "repository"=>{ "ref"=>"/repositories/2", "repository"=>{"ref"=>"/repositories/2"}, "within"=>["FID6", "S2"], "1more"=>{ a: 1, "within"=>["FID999", "S7"] } } } 

defidder hash #=> { # "lock_version"=>4, # "exhibition_quality"=>false, "within"=>["S2"], # "repository"=>{ # "ref"=>"/repositories/2", # "repository"=>{"ref"=>"/repositories/2"}, # "within"=>["S2"], # "1more"=>{:a=>1, "within"=>["S7"] # } # } 

We may verify hash was not mutated.

hash #=> { # "lock_version"=>4, # "exhibition_quality"=>false, # "within"=>["FID6", "S2"], # "repository"=>{ # "ref"=>"/repositories/2", # "repository"=>{"ref"=>"/repositories/2"}, # "within"=>["FID6", "S2"], # "1more"=>{ a: 1, "within"=>["FID999", "S7"] } # } # } 
Sign up to request clarification or add additional context in comments.

Comments

0

Assuming:

  1. Only nested hashes and no hashes in arrays.
  2. No objects in hash.

This works with your example and works with examples I created with the assumptions above:

cloned_hash = Marshal.load(Marshal.dump(hash)) def remove_key_value_pair(key, value, hash) if hash.key?(key) && hash[key] == value hash.delete(key) end hash.each{|k, v| remove_key_value_pair(key, value, v) if v.is_a? Hash } end # call with remove_key_value_pair("within", ["FID6", "S2"], cloned_hash) 

This will run into a SystemStackError if the hash has a lot of nesting.

3 Comments

Thanks @ashley . Unfortunately the hash does indeed have a lot of nesting but I didn't want to post the whole hash because it's pages long.
Try it. It still might work. Ruby's default stack is around 1MB.
Alright will do. Thank you for the help and will let you know @ashley

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.