将OpenStruct深度转换为JSON

时间:2015-10-13 00:05:15

标签: ruby

我有>>> df.groupby("Dept")["User"].nunique() Dept Cook 2 Home 1 Sports 1 Travel 1 Name: User, dtype: int64 >>> df.groupby("Dept")["User"].nunique().reset_index() Dept User 0 Cook 2 1 Home 1 2 Sports 1 3 Travel 1 与许多其他OpenStruct嵌套。将它们全部转换为JSON的最佳方法是什么?

理想情况下:

OpenStructs

现实

x = OpenStruct.new
x.y = OpenStruct.new
x.y.z = OpenStruct.new
z = 'hello'

x.to_json
// {y: z: 'hello'}

4 个答案:

答案 0 :(得分:9)

没有默认方法可以完成此类任务,因为内置的#to_hash会返回哈希表示,但它并没有深度转换值。

如果某个值为OpenStruct,则会将其返回,并且不会转换为Hash

然而,解决这个问题并不复杂。您可以创建一个遍历OpenStruct实例中每个键/值的方法(例如,使用each_pair),如果值为OpenStruct,则以递归方式下降到嵌套OpenStruct中并返回Hash只是Ruby基本类型。

然后可以使用Hash.to_json轻松序列化此类JSON.dump(hash)

这是一个非常快速的例子

def openstruct_to_hash(object, hash = {})
  object.each_pair do |key, value|
    hash[key] = value.is_a?(OpenStruct) ? openstruct_to_hash(value) : value
  end
  hash
end

openstruct_to_hash(OpenStruct.new(foo: 1, bar: OpenStruct.new(baz: 2)))
# => {:foo=>1, :bar=>{:baz=>2}}

答案 1 :(得分:9)

修复上述解决方案以处理数组

def open_struct_to_hash(object, hash = {})
  object.each_pair do |key, value|
    hash[key] = case value
                  when OpenStruct then open_struct_to_hash(value)
                  when Array then value.map { |v| open_struct_to_hash(v) }
                  else value
                end
  end
  hash
end

答案 2 :(得分:1)

这是从lancegatlin的答案修改而来的另一种方法。还将方法添加到OpenStruct类本身。

class OpenStruct
  def deep_to_h
    each_pair.map do |key, value|
      [
        key,
        case value
          when OpenStruct then value.deep_to_h
          when Array then value.map {|el| el === OpenStruct ? el.deep_to_h : el}
          else value
        end
      ]
    end.to_h
  end

答案 3 :(得分:0)

相同的函数也可以接受数组作为输入

  def openstruct_to_hash(object, hash = {})
    case object
    when OpenStruct then
      object.each_pair do |key, value|
        hash[key] = openstruct_to_hash(value)
      end
      hash
    when Array then
      object.map { |v| openstruct_to_hash(v) }
    else object
    end
  end