24

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

I'm working in Ruby 1.9.2.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
B Seven
  • 44,484
  • 66
  • 240
  • 385
  • 1
    Short answer is no, hashes need to have unique keys. Why would you need to have a hash with duplicate keys? – Thiago Jackiw Jul 24 '11 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? – Ray Toal Jul 24 '11 at 18:37
  • *You don't want this*, you'd need to ruin performance to allow this. –  Jul 24 '11 at 19:08
  • 1
    @Thiago, that's a sort of medium answer. The short answer is "No" :) – John La Rooy Jul 25 '11 at 05:40
  • Perhaps reading [the documentation](http://ruby-doc.org/core-2.3.0/Hash.html) would help: "A Hash is a dictionary-like collection of unique keys and their values." – the Tin Man Mar 28 '16 at 23:21

2 Answers2

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}
steenslag
  • 79,051
  • 16
  • 138
  • 171
  • 2
    The first example is exactly what I was looking for. Awesome. – B Seven Sep 16 '13 at 20:09
  • 1
    Hello Steenslag, i used "compare_by_identity" for creating hash with duplicate keys. But it is not working. Will you please help me. – Buddy Apr 29 '14 at 11:25
  • 1
    @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. – steenslag Apr 29 '14 at 21:52
  • You had me going there for a moment... the first example is what I needed right now. It works with Ruby 1.9.3 but not with Ruby 2.2.1 (just two versions selected for a quick test). – starfry Dec 04 '17 at 14:00
  • 2
    Strange... it does not work on 2.3.3, but it does work on 2.4.2 ?! – steenslag Dec 04 '17 at 14:32
  • 1
    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. – ivanibash May 15 '18 at 10:07
  • So, How can I get value of key from h1 hash ?? – code_aks Jun 26 '19 at 04:43
  • i tried this but somehow doesn't work, i used this instead and it works for me https://stackoverflow.com/a/36336793/11976278 – Karin Jun 29 '22 at 04:29
33

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]}
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
  • 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 }` – Cyril Duchon-Doris Feb 17 '15 at 18:27
  • 2
    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. – Michael Kohl Feb 18 '15 at 06:05
  • 2
    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. – Emile Vrijdags Aug 02 '17 at 07:50
  • 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. https://github.com/doxavore/multimap. – Michael Kohl Aug 02 '17 at 08:51