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.

  • 1
    You should consider highlighting the ways that this question differs from your [suspiciously similar question](https://stackoverflow.com/questions/62565657/how-would-i-remove-multiple-nested-values-from-a-hash) from a few days back. – Simple Lime Jun 29 '20 at 01:54
  • Hi yes I will do that. Thanks for the suggestion @SimpleLime – Hannah Baker Jun 29 '20 at 01: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"]`. – Cary Swoveland Jun 29 '20 at 03:22
  • Does this answer your question? [How would I remove multiple nested values from a hash](https://stackoverflow.com/questions/62565657/how-would-i-remove-multiple-nested-values-from-a-hash) – Kache Jun 29 '20 at 04:11

2 Answers2

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"] }
  #     }
  #   }
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
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.

Ashley
  • 2,256
  • 1
  • 33
  • 62