Skip to content

Instantly share code, notes, and snippets.

@NigelThorne
Last active October 25, 2017 05:43
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save NigelThorne/2913760 to your computer and use it in GitHub Desktop.
Save NigelThorne/2913760 to your computer and use it in GitHub Desktop.
ruby hash invert
require './hash_inverse'
describe Hash do
describe "when empty and asked for the inverse" do
it "returns an empty hash" do
{}.inverse.must_equal Hash.new
end
end
describe "when mapping are unique and asked for the inverse" do
it "returns the inverse hash" do
{a: 1, b: 2, c: 3}.inverse.must_equal({1=>[:a], 2=>[:b], 3=>[:c]})
end
end
describe "when mapping are not unique and asked for the inverse" do
it "returns the one to many key to values" do
{a: 1, b: 1, c: 2}.inverse.must_equal({1=>[:a, :b], 2=>[:c]})
end
end
end
class Hash
# like invert but not lossy
#{1=>2,3=>2,2=>4}.inverse => {2=>[1, 3], 4=>[2]}
def inverse
self.each_with_object( {} ) { |(key, value), out| ( out[value] ||= [] ) << key }
end
end
@obfuscoder
Copy link

Shorter:

self.each_with_object({}){|(k,v),o| (o[v] ||=[]) << k}

or with reduce:

self.reduce({}){|h,(k,v)| (h[v] ||=[]) << k; h}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment