multikey_hash.rb
class MultikeyHash | |
include Enumerable | |
def initialize(initial_values = nil) | |
@outer_hash = {} | |
@inner_hash = {} | |
@next_inner_key = 1 | |
if initial_values | |
initial_values.each do |keys, value| | |
if keys.is_a?(Array) && !keys.empty? | |
keys.each do |key| | |
self[key] = value | |
end | |
else | |
self[keys] = value | |
end | |
end | |
end | |
end | |
def [](outer_key) | |
inner_key = @outer_hash[outer_key] | |
if inner_key.nil? | |
nil | |
else | |
@inner_hash[inner_key] | |
end | |
end | |
def []=(outer_key, new_value) | |
inner_key = @inner_hash.select { |_, existing_value| existing_value == new_value }.map { |key, _| key }.first | |
if inner_key | |
@outer_hash[outer_key] = inner_key | |
else | |
@outer_hash[outer_key] = @next_inner_key | |
@inner_hash[@next_inner_key] = new_value | |
@next_inner_key += 1 | |
end | |
end | |
def each(&block) | |
@outer_hash.group_by { |_, inner_key| inner_key }.inject({}) { |acc, e| acc[e.last.map { |i| i.first }] = @inner_hash[e.first]; acc }.each do |key, value| | |
block.call(key, value) | |
end | |
end | |
def inspect | |
"{#{self.map { |keys, value| "#{keys.inspect}=>#{value.inspect}" }.join(', ')}}" | |
end | |
def to_s | |
inspect | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment