将对象转换为哈希

假设我有一个具有 @name = "book"@price = 15.95Gift对象。在 Ruby 而不是 Rails 中将它转换为 Hash{name: "book", price: 15.95}的最佳方法是什么(尽管也可以给出 Rails 的答案) ?

161100 次浏览

您应该重写对象的 inspect方法以返回所需的散列,或者只是实现一个类似的方法而不重写默认的对象行为。

如果你想要更好,你可以用 Instance _ variable迭代一个对象的实例变量

class Gift
def initialize
@name = "book"
@price = 15.95
end
end


gift = Gift.new
hash = {}
gift.instance_variables.each {|var| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}

或者与 each_with_object一起使用:

gift = Gift.new
hash = gift.instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}
class Gift
def to_hash
instance_variables.map do |var|
[var[1..-1].to_sym, instance_variable_get(var)]
end.to_h
end
end

实现 #to_hash

class Gift
def to_hash
hash = {}
instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) }
hash
end
end




h = Gift.new("Book", 19).to_hash

活动记录对象

module  ActiveRecordExtension
def to_hash
hash = {}; self.attributes.each { |k,v| hash[k] = v }
return hash
end
end


class Gift < ActiveRecord::Base
include ActiveRecordExtension
....
end


class Purchase < ActiveRecord::Base
include ActiveRecordExtension
....
end

然后打电话给我

gift.to_hash()
purch.to_hash()
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}

只要说(当前对象) .attributes

.attributes返回任何 objecthash,而且它也更干净。

使用‘ hash’gem (https://rubygems.org/gems/hashable)递归地将对象转换为 hash 例子

class A
include Hashable
attr_accessor :blist
def initialize
@blist = [ B.new(1), { 'b' => B.new(2) } ]
end
end


class B
include Hashable
attr_accessor :id
def initialize(id); @id = id; end
end


a = A.new
a.to_dh # or a.to_deep_hash
# {:blist=>[{:id=>1}, {"b"=>{:id=>2}}]}

只生成模型属性的浅表副本作为哈希对象

my_hash_gift = gift.attributes.dup

检查结果对象的类型

my_hash_gift.class
=> Hash

您可以使用函数样式编写一个非常优雅的解决方案。

class Object
def hashify
Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }]
end
end

如果您不在 Rails 环境中(例如,没有 ActiveRecord 可用) ,这可能会有所帮助:

JSON.parse( object.to_json )

如果还需要转换嵌套对象。

# @fn       to_hash obj \{\{{
# @brief    Convert object to hash
#
# @return   [Hash] Hash representing converted object
#
def to_hash obj
Hash[obj.instance_variables.map { |key|
variable = obj.instance_variable_get key
[key.to_s[1..-1].to_sym,
if variable.respond_to? <:some_method> then
hashify variable
else
variable
end
]
}]
end # }}}

也许你该试试 instance_values这招对我管用。

您可以使用 as_json方法。它会将您的对象转换为散列。

但是,散列将作为该对象的名称的值作为键,

{'gift' => {'name' => 'book', 'price' => 15.95 }}

如果需要存储在对象中的散列,请使用 as_json(root: false)。我认为默认情况下 root 值为 false。更多信息请参考官方红宝石指南

Http://api.rubyonrails.org/classes/activemodel/serializers/json.html#method-i-as_json

符号键

要在不使用 Rails 的情况下实现这一点,一种干净的方法是将属性存储在常量上。

class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
end

然后,要将 Gift的实例转换为 Hash,您可以:

class Gift
...
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end

这是一个很好的方法,因为它只包括你在 attr_accessor上定义的内容,而不是每个实例变量。

class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)


def create_random_instance_variable
@xyz = 123
end


def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end


g = Gift.new
g.name = "Foo"
g.price = 5.25
g.to_h
#=> {:name=>"Foo", :price=>5.25}


g.create_random_instance_variable
g.to_h
#=> {:name=>"Foo", :price=>5.25}

我开始使用结构来简化哈希转换。 我不使用一个空的结构,而是创建我自己的类派生自一个散列,这允许你创建你自己的函数,它记录了一个类的属性。

require 'ostruct'


BaseGift = Struct.new(:name, :price)
class Gift < BaseGift
def initialize(name, price)
super(name, price)
end
# ... more user defined methods here.
end


g = Gift.new('pearls', 20)
g.to_h # returns: {:name=>"pearls", :price=>20}

要在上面的评论中剽窃@Mr. L,请尝试 @gift.attributes.to_options

根据内特的回答,我还没有能够编译:

选择一

class Object
def to_hash
instance_variables.map{ |v| Hash[v.to_s.delete("@").to_sym, instance_variable_get(v)] }.inject(:merge)
end
end

然后你就这么说:

my_object.to_hash[:my_variable_name]

选择二

class Object
def to_hash
instance_variables.map{ |v| Hash[v.to_s.delete("@"), instance_variable_get(v)] }.inject(:merge)
end
end

然后你就这么说:

my_object.to_hash["my_variable_name"]

你可以使用 symbolize_keys,如果你有嵌套的属性,我们可以使用 deep_symbolize_keys:

gift.as_json.symbolize_keys => {name: "book", price: 15.95}