23

Is it possible to create a hash in Ruby that allows duplicate keys?

I'm working in Ruby 1.9.2.

5
  • 1
    Short answer is no, hashes need to have unique keys. Why would you need to have a hash with duplicate keys? Commented Jul 24, 2011 at 18:36
  • 1
    Do you mean an instance of the class Hash that has two entries, each of which with the same exact key? Commented Jul 24, 2011 at 18:37
  • You don't want this, you'd need to ruin performance to allow this. Commented Jul 24, 2011 at 19:08
  • 1
    @Thiago, that's a sort of medium answer. The short answer is "No" :) Commented Jul 25, 2011 at 5:40
  • Perhaps reading the documentation would help: "A Hash is a dictionary-like collection of unique keys and their values." Commented Mar 28, 2016 at 23:21

2 Answers 2

48

Two ways of achieving duplicate keys in a hash:

h1 = {}
h1.compare_by_identity
h1["a"] = 1
h1["a"] = 2
p h1 # => {"a"=>1, "a"=>2}


h2 = {}
a1 = [1,2,3]
a2 = [1,2]
h2[a1] = 1
h2[a2] = 2
a2 << 3 
p h2 # => {[1, 2, 3]=>1, [1, 2, 3]=>2}
Sign up to request clarification or add additional context in comments.

8 Comments

The first example is exactly what I was looking for. Awesome.
Hello Steenslag, i used "compare_by_identity" for creating hash with duplicate keys. But it is not working. Will you please help me.
@Buddy What are you using as keys? Integers and symbols can't work, there is only one 1 and one :a - duplicates are impoissible. compare_by_identity works by comparing object_id's, normal hashes compare by comparing the result of the eql? method.
Strange... it does not work on 2.3.3, but it does work on 2.4.2 ?!
We had a similar problem at my company and my boss came up with a solution to make the first example work in all ruby versions. Basically in some rubies (latest?) it seems like when you write h1['a'] two times, a string object gets created with different ids. This is not the case in som other versions. In other versions when you write h1['a'] twice the id of that 'a' will be the same each time. A workaround is to do h1['a'.clone] to create a new string object.
|
32

This would kinda defeat the purpose of a hash, wouldn't it?

If you want a key to point to multiple elements, make it point to an array:

h = Hash.new { |h,k| h[k] = [] }
h[:foo] << :bar
h #=> {:foo=>[:bar]}
h[:foo] << :baz
h #=> {:foo=>[:bar, :baz]}

4 Comments

It actually depends on the context. For example, in LDAP systems, you can have multiple objectClass, and yes, you can define a hash like this one : attrs = { ..., displayName: user.short_name, objectClass: "organizationPerson", objectClass: "person", objectClass: "top", objectClass: "user", i }
That may well be the case, but that doesn't turn it into an associative array (which is what Ruby hashes are). "In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears just once in the collection." Emphasis added.
C++ has multimaps and multisets that allow multiple keys with the same name. From that same wikipedia page on associative arrays: "A multimap generalizes an associative array by allowing multiple values to be associated with a single key." So I would not say it defeats the purpose.. but its just a different, and valid usecase.
Sure, but if you look at the C++ template for multimap you'll also see that it's a more complex data structure than a simple associative array which is what Ruby hashes are. There are multimap gems for Ruby, e.g. github.com/doxavore/multimap.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.