루비는 객체를 해시로 변환


127

& Gift객체를 가지고 있다고 가정 해 봅시다 . Rails가 아닌 Ruby 에서 해시로 변환하는 가장 좋은 방법은 무엇입니까 ? (Rails도 자유롭게 대답 할 수는 있지만)?@name = "book"@price = 15.95{name: "book", price: 15.95}


16
@ gift.attributes.to_options는 하시겠습니까?
Mr. L

1
1) 선물은 ​​ActiveRecord 개체입니까? 2) @ name / @ price가 인스턴스 변수 일뿐만 아니라 독자 접근 자라고 가정 할 수 있습니까? 3) 선물의 이름과 가격 또는 모든 속성 만 원하십니까?
tokland

@tokland, 1) 아니, Gift이다 @nash가 정의 된 것처럼 정확하게 , 확인, 인스턴스 변수가 독자의 접근을 할 수 있습니다), (2)를 제외시켰다. 3) 선물의 모든 속성.
ma11hew28

확인. 인스턴스 변수 / 리더 액세스에 대한 질문은 외부 액세스 (nash) 또는 내부 메소드 (levinalex)가 필요한지 아는 것이 었습니다. "내부"접근 방식에 대한 답변을 업데이트했습니다.
tokland

답변:


80
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}

3
inject를 사용하여 변수 초기화를 건너 뛸 수 있습니다. gift.instance_variables.inject ({}) {| hash, var | hash [var.to_s.delete ( "@")] = gift.instance_variable_get (var); 해시}
요르단

8
좋은. 기호를 얻기 위해 교체 var.to_s.delete("@")했습니다 var[1..-1].to_sym.
ma11hew28

3
주입, 사용 gift.instance_variables.each_with_object({}) { |var,hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }및 후행을 제거 하지 마십시오; hash
Narfanator

1
나는 루비 페티쉬를 결코 이해하지 못할 것이다 each. map그리고 inject훨씬 더 강력하다. 이것은 Ruby와 함께하는 하나의 디자인 자료 map이며 inject로 구현됩니다 each. 단순히 컴퓨터 과학이 나쁘다.
Nate Symer

약간 더 간결한 :hash = Hash[gift.instance_variables.map { |var| [var.to_s[1..-1], gift.instance_variable_get(var)] } ]
Marvin


48

구현 #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

#은 클래스 메소드를 나타내므로 기술적으로 .to_hash 여야합니다.
Caleb

6
사실은 아닙니다. RDoc 문서는 다음과 같이 말합니다. Use :: for describing class methods, # for describing instance methods, and use . for example code(source : ruby-doc.org/documentation-guidelines.html ) 또한 공식 문서 (예 : ruby ​​CHANGELOG, github.com/ruby/ruby/blob/v2_1_0/NEWS )는 #인스턴스 메소드와 도트를 사용합니다. 클래스 메소드의 경우 꽤 일관성이 있습니다.
levinalex

이 반 패턴 대신에 주사제를 사용하십시오.
YoTengoUnLCD

다음을 사용하는 한 줄짜리 변형 each_with_object:instance_variables.each_with_object(Hash.new(0)) { |element, hash| hash["#{element}".delete("@").to_sym] = instance_variable_get(element) }
anothermh

43
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}

10
이것은 Rails이며 Ruby 자체에는 없습니다 instance_values. Matt는 특별히 Rails가 아닌 Ruby 방식을 요청했습니다.
Christopher Creutzig

28
그는 Rails에 대한 답변도 자유롭게 해주겠다고 말했다.
Erik Reedstrom

하나님은 두 가지 버전을 여기에서 볼 수 있습니다.) 좋아요
Sebastian Schürmann

17

as_json방법 을 사용할 수 있습니다 . 객체를 해시로 변환합니다.

그러나 해시는 해당 객체의 이름에 키로 사용됩니다. 귀하의 경우

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

객체에 저장된 해시가 필요한 경우을 사용하십시오 as_json(root: false). 나는 기본적으로 루트가 거짓이라고 생각합니다. 자세한 내용은 공식 루비 가이드를 참조하십시오

http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json


13

활성 레코드 객체

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() 

2
재미있는 것은 Rails 프레임 워크의 일부가 아닙니다. 거기에있는 것이 유용한 것 같습니다.
Magne

attributes 메소드는 값이있는 새 해시를 리턴하므로 to_hash 메소드에서 다른 해시를 작성할 필요가 없습니다. 이와 같이 : attribute_names.each_with_object ({}) {| name, attrs | attrs [name] = read_attribute (name)}입니다. 여기를 참조하십시오 : github.com/rails/rails/blob/master/activerecord/lib/…
Chris Kimpton

당신은지도로 이것을 할 수 있었으며, 부작용 구현이 내 마음을 아프게합니다!
Nate Symer


11
class Gift
  def to_hash
    instance_variables.map do |var|
      [var[1..-1].to_sym, instance_variable_get(var)]
    end.to_h
  end
end

6

기능적 스타일을 사용하여 매우 우아한 솔루션을 작성할 수 있습니다.

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

4

당신은 오버라이드 (override) 할 필요가 inspect원하는 해시를 반환하는 개체의 방법을, 아니면 그냥 기본 객체의 행동을 무시하지 않고 유사한 방법을 구현한다.

더 멋지게 만들고 싶다면 object.instance_variables를 사용하여 객체의 인스턴스 변수를 반복 할 수 있습니다.


4

반복적으로 사용하여 해시 개체를 변환 '해쉬'보석 ( https://rubygems.org/gems/hashable )

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}}]}

4

시도하고 싶을 수도 instance_values있습니다. 그것은 나를 위해 일했다.


1

단순 속성을 모델 속성의 해시 객체로 생성

my_hash_gift = gift.attributes.dup

결과 객체의 유형을 확인하십시오.

my_hash_gift.class
=> Hash

0

중첩 객체도 변환해야하는 경우

# @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 # }}}


0

Rails없이이 작업을 수행하려면 속성을 상수에 저장하는 것이 좋습니다.

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

그리고, 인스턴스 변환하는 GiftA와 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}

0

해시 변환을 쉽게하기 위해 구조체를 사용하기 시작했습니다. 베어 구조를 사용하는 대신 해시에서 파생 된 자체 클래스를 작성하면 자체 함수를 작성하고 클래스의 특성을 문서화 할 수 있습니다.

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}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.