将散列转换为结构体

时间:2022-12-15 20:48:29

How can I convert a hash into a struct in ruby?

如何将散列转换为ruby中的结构体?

Given this:

鉴于这种:

h = { :a => 1, :b => 2 }

I want a struct such that:

我想要一个结构体:

s.a == 1
s.b == 2

8 个解决方案

#1


52  

If it doesn't specifically have to be a Struct and instead can be an OpenStruct:

如果它不是一个结构体,而是一个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

#2


57  

If you already have a struct defined, and you want to instantiate an instance with a hash:

如果您已经定义了一个结构体,并且想用散列实例化一个实例:

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>

#3


48  

Since Hash key order is guaranteed in Ruby 1.9+:

由于哈希键顺序在Ruby 1.9+中得到了保证:

Struct.new(*h.keys).new(*h.values)

#4


8  

The following creates a struct from a hash in a reliable way (since hash order is not guaranteed in ruby):

下面以一种可靠的方式从散列中创建一个结构体(因为在ruby中不保证散列顺序):

s = Struct.new(*(k = h.keys)).new(*h.values_at(*k))

#5


2  

Having Hash#to_struct is quite practical:

拥有Hash#to_struct是非常实际的:

class Hash
  def to_struct
    Struct.new(*keys).new(*values)
  end
end

And some examples:

和一些例子:

>> { 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>

Deep to_struct that works with arrays:

使用数组的深度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

#6


1  

Here's an example to map the values to the proper order of the Struct:

下面的示例将值映射到结构体的适当顺序:

require 'securerandom'

Message = Struct.new(:to, :from, :message, :invitee)

message_params = {from: "my@email.address", to: "your@email.address",
        invitee: SecureRandom.uuid, message: "hello"}

if Message.members.sort == message_params.keys.sort
  # Do something with the return struct object here
  Message.new *Message.members.map {|k| message_params[k] } 
else
  raise "Invalid keys for Message"
end

#7


0  

This gives a clean plain read-only object, similar to a ruby Struct but with deep conversion and extra to_h method to get struct at any point as Hash.

这提供了一个干净的普通只读对象,类似于ruby Struct,但具有深度转换和额外的to_h方法,以在任何时候作为散列来获得Struct。

Example

例子

foo = {a:{b:{c:123}}}.to_struct
foo.a.b.c # 123
foo.a.to_h # {b:{c:123}}

Ruby code

Ruby代码

class Hash
  def to_struct
    Class.new.tap do |c|
      c.define_singleton_method(:to_h) do
        m_list = methods(false) - [:to_h]
        m_list.inject({}) do |h, m|
          h[m] = send(m)
          h[m] = h[m].to_h if h[m].class == Class
          h
        end
      end

      each do |k, v|
        v = v.to_struct if v.class == Hash
        c.define_singleton_method(k) { v }
      end
    end
  end
end

Not exactly the answer to a question (not a ruby Struct object), but I needed just this while looking for an answer, so I will just post the answer here.

不完全是问题的答案(不是ruby Struct对象),但是在寻找答案时,我需要这个,所以我将在这里发布答案。

#8


-1  

require 'ds_hash'

data = {a: {b: 123 }}.to_struct

data.a.b == 123       # true
data.a   == {b: 123 } # true

#1


52  

If it doesn't specifically have to be a Struct and instead can be an OpenStruct:

如果它不是一个结构体,而是一个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

#2


57  

If you already have a struct defined, and you want to instantiate an instance with a hash:

如果您已经定义了一个结构体,并且想用散列实例化一个实例:

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>

#3


48  

Since Hash key order is guaranteed in Ruby 1.9+:

由于哈希键顺序在Ruby 1.9+中得到了保证:

Struct.new(*h.keys).new(*h.values)

#4


8  

The following creates a struct from a hash in a reliable way (since hash order is not guaranteed in ruby):

下面以一种可靠的方式从散列中创建一个结构体(因为在ruby中不保证散列顺序):

s = Struct.new(*(k = h.keys)).new(*h.values_at(*k))

#5


2  

Having Hash#to_struct is quite practical:

拥有Hash#to_struct是非常实际的:

class Hash
  def to_struct
    Struct.new(*keys).new(*values)
  end
end

And some examples:

和一些例子:

>> { 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>

Deep to_struct that works with arrays:

使用数组的深度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

#6


1  

Here's an example to map the values to the proper order of the Struct:

下面的示例将值映射到结构体的适当顺序:

require 'securerandom'

Message = Struct.new(:to, :from, :message, :invitee)

message_params = {from: "my@email.address", to: "your@email.address",
        invitee: SecureRandom.uuid, message: "hello"}

if Message.members.sort == message_params.keys.sort
  # Do something with the return struct object here
  Message.new *Message.members.map {|k| message_params[k] } 
else
  raise "Invalid keys for Message"
end

#7


0  

This gives a clean plain read-only object, similar to a ruby Struct but with deep conversion and extra to_h method to get struct at any point as Hash.

这提供了一个干净的普通只读对象,类似于ruby Struct,但具有深度转换和额外的to_h方法,以在任何时候作为散列来获得Struct。

Example

例子

foo = {a:{b:{c:123}}}.to_struct
foo.a.b.c # 123
foo.a.to_h # {b:{c:123}}

Ruby code

Ruby代码

class Hash
  def to_struct
    Class.new.tap do |c|
      c.define_singleton_method(:to_h) do
        m_list = methods(false) - [:to_h]
        m_list.inject({}) do |h, m|
          h[m] = send(m)
          h[m] = h[m].to_h if h[m].class == Class
          h
        end
      end

      each do |k, v|
        v = v.to_struct if v.class == Hash
        c.define_singleton_method(k) { v }
      end
    end
  end
end

Not exactly the answer to a question (not a ruby Struct object), but I needed just this while looking for an answer, so I will just post the answer here.

不完全是问题的答案(不是ruby Struct对象),但是在寻找答案时,我需要这个,所以我将在这里发布答案。

#8


-1  

require 'ds_hash'

data = {a: {b: 123 }}.to_struct

data.a.b == 123       # true
data.a   == {b: 123 } # true