Crystal - 如何递归更改哈希值并将每个更改保存到新哈希

Ba7*_*chy 0 crystal-lang

使用这个Hash对象

{"foo" => {"bar" => 1, "baz" => 2}, "bla" => [1,2,3]}
Run Code Online (Sandbox Code Playgroud)

我想生成这个Hash对象数组

[
  {"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" => "*"}, 
]
Run Code Online (Sandbox Code Playgroud)

我基本上遍历了每个键并将其值更改为"*",同时保留了散列的整体结构并保存了在某个数组中生成的新散列.

我已经尝试了很多想法,但大多数都不会工作,因为我之前可以猜到Array类型,我只知道这个哈希是由JSON.parse生成的,然后变成Hash(String,JSON :: Any)

我目前正在尝试它

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
Run Code Online (Sandbox Code Playgroud)

Ole*_*pin 5

Crystal v0.25.0 实现了没有递归别名的JSON :: Any和YAML :: Any.有了这个改变:

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")
Run Code Online (Sandbox Code Playgroud)
*
{"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" => "*"}
Run Code Online (Sandbox Code Playgroud)