Set two keys for one value in Hash in Rails

59 views Asked by At

Let's say I have a hash:

{
  first: :value1,
  second: :value1,
  third: :value2 
}

During .map I need to eliminate duplicates so it should be either first or second only. Is it possible to have some workaround like:

{
  (:first || :second) => :value1,
  third: :value2 
}

If not, how can I remove key duplicates in a hash based on condition? Is it possible to pass a condition into the .uniq block?

Thanks,

3

There are 3 answers

3
David On

Yes, it is possible to pass a block to the #uniq method.

https://ruby-doc.org/3.2.2/Enumerable.html#method-i-uniq

You can apply something like:

hash.uniq { |_k, v| v }

or shorter:

hash.uniq(&:last)

Also, another correct solution if you don't need the keys is to simply take the values:

hash.values.uniq

The second recommendation of yours is valid Ruby code, but incorrect, as it removes one key and evaluates to the following:

irb(main):004:0> {
  (:first || :second) => :value1,
  third: :value2
}
=> {:first=>:value1, :third=>:value2}
1
nitsas On

You can also use Hash#invert, to make the hash point from each unique value to a single key. It will keep the last key for each value:

hash = {
  first: :value1,
  second: :value1,
  third: :value2 
}

hash.invert
# => {
#   :value1=> :second,
#   :value2=> :third
# }

Then you can iterate over that or use it any way you like.

0
mechnicov On
hsh =
  {
    first: :value1,
    second: :value1,
    third: :value2 
  }

hsh.uniq { _2 }.to_h
# => {:first=>:value1, :third=>:value2}

Firstly call uniq with block and numbered parameter. It returns array of arrays where second elements are unique (take first pair)

ary = hsh.uniq { _2 }
# => [[:first, :value1], [:third, :value2]]

And convert array to hash

ary.to_h
# => {:first=>:value1, :third=>:value2}