将哈希转换为结构

alf*_*alf 43 ruby

如何将哈希转换为ruby中的结构?

鉴于这种:

h = { :a => 1, :b => 2 }
Run Code Online (Sandbox Code Playgroud)

我想要一个结构,这样:

s.a == 1
s.b == 2
Run Code Online (Sandbox Code Playgroud)

ela*_*ado 67

如果已经定义了结构,并且希望使用哈希实例化实例:

Person = Struct.new(:first_name, :last_name, :age)

person_hash = { first_name: "Foo", last_name: "Bar", age: 29 }

person = Person.new(*person_hash.values_at(*Person.members))

=> #<struct Person first_name="Foo", last_name="Bar", age=29>
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案:)。谢谢! (2认同)

Dav*_*ton 60

如果它没有特别必须是a Struct而是可以是OpenStruct:

pry(main)> require 'ostruct'
pry(main)> s = OpenStruct.new(h)
=> #<OpenStruct a=1, b=2>
pry(main)> puts s.a, s.b
1
2
Run Code Online (Sandbox Code Playgroud)

  • @DaveNewton:不在这个页面上他们没有.或者在许多推荐使用它们的网站上.最初的问题要求一个结构 - 我认为这只是礼貌 - 警告使用不同的解决方案固有的权衡. (6认同)
  • 请注意,OpenStructs的使用速度极慢.对于少量小物体来说很好,但是它们的尺度很差.这里有一些进一步的信息:http://stackoverflow.com/questions/1177594/ruby-struct-vs-openstruct (5认同)

Phr*_*ogz 51

由于Ruby 1.9+中保证了Hash键顺序:

Struct.new(*h.keys).new(*h.values)
Run Code Online (Sandbox Code Playgroud)

  • @Joe minor correction:NameError的真正原因是因为如果你提供了一个字符串作为Struct :: new的第一个参数,它假定它是它将创建的类的名称,因此它将尝试将其转换为常量如果字符串全是小写,则失败(因为常量必须在Ruby中大写).修复是要么a)提供大写字符串作为第一个参数(Struct.new('MyClass',*h.keys))或使用符号作为ehsanul建议的哈希键. (3认同)
  • @Joe它确实很好用.我认为您使用字符串键作为哈希,这是导致错误的原因.错误告诉您它需要一个常量值,即符号而不是字符串.我可以在2.1.5中重现错误,如果我切换到符号就会消失. (2认同)
  • 遇到与 Joe 相同的问题,必须先转换我的字符串参数:```Struct.new(*h.keys.map(&amp;:to_sym)).new(*h.values)``` (2认同)

8bi*_*ero 9

这是基于@elado 上面的回答,但使用keyword_init值(结构文档

你可以简单地这样做:

Person = Struct.new(:first_name, :last_name, :age, keyword_init: true)

person_hash = { first_name: "Foo", last_name: "Bar", age: 29 }

person = Person.new(person_hash)

=> #<struct Person first_name="Foo", last_name="Bar", age=29>
Run Code Online (Sandbox Code Playgroud)


alf*_*alf 8

以下以可靠的方式从哈希创建结构(因为在ruby中不保证哈希顺序):

s = Struct.new(*(k = h.keys)).new(*h.values_at(*k))
Run Code Online (Sandbox Code Playgroud)


Dor*_*ian 8

Hash#to_struct很实用:

class Hash
  def to_struct
    Struct.new(*keys).new(*values)
  end
end
Run Code Online (Sandbox Code Playgroud)

还有一些例子:

>> { a: 1, b: 2 }.to_struct
=> #<struct a=1, b=2>
>> { a: 1, b: 2 }.to_struct.a
=> 1
>> { a: 1, b: 2 }.to_struct.b
=> 2
>> { a: 1, b: 2 }.to_struct.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
Run Code Online (Sandbox Code Playgroud)

to_struct与数组一起使用的深度:

class Array
  def to_struct
    map { |value| value.respond_to?(:to_struct) ? value.to_struct : value }
  end
end

class Hash
  def to_struct
    Struct.new(*keys).new(*values.to_struct)
  end
end
Run Code Online (Sandbox Code Playgroud)