0

using this Hash object

{"foo" => {"bar" => 1, "baz" => 2}, "bla" => [1,2,3]}

I want to produce this array of Hash objects

[
  {"foo" => "*", "bla" => [1,2,3]},
  {"foo" => {"bar" => "*", "baz" => 2}, "bla" => [1,2,3]},
  {"foo" => {"bar" => "1", "baz" => "*"}, "bla" => [1,2,3]},
  {"foo" => {"bar" => "*", "baz" => 2}, "bla" => "*"}, 
]

Where I basically went over each key and changed its value to "*" while preserving the overall structure of the hash and saved the new hash produced in some array.

I have tried many ideas, but most just wont work as I can guess the Array type before, I only know this hash is produced by JSON.parse and then changed into Hash(String, JSON::Any)

My current try at it

hash = {"bar" => {"and" => "2", "br" => "1"}}
arr = [hash, {"bar" => "1"}]
arr.delete(arr.last)
arr.delete(hash)

def changer(hash, arr, original = nil)
  original = hash.dup
  hash.each do |k, v|
    if v.is_a?(Hash)
       changer(v, arr, hash)
    elsif v.is_a?(Array)
      v.each do |a|
        if a.is_a?(Hash)
            changer(a, arr, hash)
        end  
        end
  elsif v.is_a?(String) && original.is_a?(Hash(String, String))
      original[k.to_s] = "*"
      arr << original
    end
  end
end
Ba7a7chy
  • 1,471
  • 4
  • 14
  • 29
  • Your example code in your "try at it" section has nothing but Strings in your hash, but your stated problem has Int values as well. Do you have a well defined schema for your JSON? – voxobscuro Feb 14 '18 at 13:24
  • FWIW, [Ruby](https://carc.in/#/r/3l30) vs [Crystal](https://carc.in/#/r/3l32) compilation error. – Oleh Prypin Feb 14 '18 at 17:35

1 Answers1

6

Crystal v0.25.0 implements JSON::Any and YAML::Any without recursive aliases. With that change:

require "json"

hash = JSON.parse(%(
  {"foo": {"bar": 1, "baz": 2}, "bla": [1,2,3]}
))

def changer(any : JSON::Any)
  result = [JSON::Any.new("*")]
  if (hash = any.as_h?)
    hash.each do |key, value|
      changer(value).each do |s|
        result << JSON::Any.new(hash.merge({key => s}))
      end
    end
  end
  result
end

puts changer(hash).join("\n")
*
{"foo" => "*", "bla" => [1_i64, 2_i64, 3_i64]}
{"foo" => {"bar" => "*", "baz" => 2_i64}, "bla" => [1_i64, 2_i64, 3_i64]}
{"foo" => {"bar" => 1_i64, "baz" => "*"}, "bla" => [1_i64, 2_i64, 3_i64]}
{"foo" => {"bar" => 1_i64, "baz" => 2_i64}, "bla" => "*"}
voxobscuro
  • 2,132
  • 1
  • 21
  • 45
Oleh Prypin
  • 33,184
  • 10
  • 89
  • 99