创建数据结构而不复制键

时间:2011-03-31 17:56:12

标签: ruby data-structures

我有多个具有以下两个哈希表的类。两个映射都必须具有相同的密钥集。我的问题是有很多类具有这种结构,并且密钥集会随着时间而改变。

mapping_1 = {
  :key_1 => "attr_1_1",
  :key_2 => "attr_2_1",
  :key_3 => "attr_3_1"
}

mapping_2 = {
  :key_1 => "attr_1_2",
  :key_2 => "attr_2_2",
  :key_3 => "attr_3_2"
}

我需要能够访问给定两个映射的键的值以及映射1的值中的键。换句话说,我需要能够执行这些操作:

mapping_1[:key_1]
mapping_1.index("attr_2_1")  #(Ruby 1.8.7)
mapping_2[:key_3]

问题:有没有办法让我不必复制两种结构中的密钥?

我想过将数据映射到数组(:key_1 => ["attr_1_1", "attr_1_2"]),但这不起作用,因为当我运行命令mapping_1.index()时,我不知道第二个属性的值是什么

5 个答案:

答案 0 :(得分:1)

我认为你应该创建自己的哈希类并使用它代替Hash。它会处理密钥集,并包装每个对象的存储空间。

它可以使用类方法来编辑您的密钥集,例如:

def self.add_key(key, default_value)
def self.remove_key(key)

和您将在容器类中使用的实例方法,它们将模仿Hash方法:

def get(key)
def set(key, value)
def find_key(value)

等。当然,您可以使用普通Hash作为底层存储。如果您需要在向任何实例添加新密钥时扩展密钥集,只需从add_key致电set

答案 1 :(得分:1)

您可以使用下面的a之类的多维数组。 Ruby的数组方法将允许您执行所需的操作。我使用find_all,甚至可能更直接。

irb(main):049:0> a
=> {"key1"=>["attr1_a", "attr1_b"], "key2"=>["attr2_a", "attr2_b"]}
irb(main):050:0> a['key2']
=> ["attr2_a", "attr2_b"]
irb(main):051:0> a.keys
=> ["key1", "key2"]
irb(main):052:0> a.keys.find_all{|k| a[k].include?('attr2_b')}
=> ["key2"]

当然,如果您像其他海报一样制作了自己的课程,那么您可以创建一种方法来进行搜索,例如a.key_containing('attr2_b')而不是上面有点凌乱的find_all字符串

答案 2 :(得分:1)

试用Multimap:https://github.com/josh/multimap。它允许每个键具有多个值并具有索引操作。请参阅此处,例如:https://github.com/josh/multimap/blob/master/lib/multimap.rb

  # call-seq:
  #   map.index(value)    => key
  #
  # Returns the key for a given value. If not found, returns
  # <tt>nil</tt>.
  #
  #   map = Multimap["a" => 100, "b" => [200, 300]]
  #   map.index(100)   #=> "a"
  #   map.index(200)   #=> "b"
  #   map.index(999)   #=> nil
  def index(value)
    invert[value]
  end

答案 3 :(得分:1)

另一种方法:

SET_OF_KEYS = [:key_1, :key_2, :key_3]

Mapping = Struct.new( *SET_OF_KEYS )
class Mapping
  def index(value)
    kv = self.each_pair.detect{|k,v| v == value }
    kv.nil? ? nil : kv.first
  end
end 

mapping_1 = Mapping.new("attr_1_1", "attr_2_1", "attr_3_1")
mapping_2 = Mapping.new("attr_1_2", "attr_2_2", "attr_3_2")

p mapping_1[:key_1]  #=> "attr_1_1"
p mapping_1.index("attr_2_1")  #=> :key_2
p mapping_2[:key_3]  #=>  "attr_3_2"

答案 4 :(得分:0)

创建一个模块并将其包含在相关的类中。

module MapHandeling
    def [] key; @map ||= {}; @map[key] end
    def []= key, value; @map ||= {}; @map[key] = value end
    def index key; @map ||= {}; @map.index(key) end
end

module MapHandeling
    def initialize map; @map = map end
    def [] key; @map[key] end
    def []= key, value; @map[key] = value end
    def index key; @map.index(key) end
end
  

A级;包括MapHandeling结束

a = A.new(some_hash)
a[:key1] = :attr1
a[:key1] #=> :attr1
a.index(:attr1) = :key1