Создание структуры данных без дублирования ключей - PullRequest
3 голосов
/ 31 марта 2011

У меня есть несколько классов, которые имеют следующие две хеш-таблицы. Оба сопоставления должны иметь одинаковый набор ключей. Моя проблема в том, что существует много классов с этой структурой, и что наборы ключей со временем изменятся.

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 ]

1 голос
/ 01 апреля 2011

Другой подход:

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"
1 голос
/ 31 марта 2011

Попробуйте 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
1 голос
/ 31 марта 2011

Вы можете использовать многомерный массив, как мой 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 строки выше

1 голос
/ 31 марта 2011

Я думаю, вам определенно следует создать свой собственный хэш-класс и использовать его вместо 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.

0 голосов
/ 31 марта 2011

Создайте модуль и включите его в соответствующие классы.

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

класс А; включает конец MapHandeling

a = A.new(some_hash)
a[:key1] = :attr1
a[:key1] #=> :attr1
a.index(:attr1) = :key1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...