Search code examples
rubyruby-2.4

How would I remove a nested value from a hash that occurs multiple times


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.


Solution

  • 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"] }
      #     }
      #   }