0

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,

mechnicov
  • 12,025
  • 4
  • 33
  • 56

3 Answers3

1

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}
David
  • 370
  • 3
  • 6
  • Thanks! Is it possible to have the second recommendation with both of them, eliminating the one that is `nil` only? So for example if hash[:first] is nil I'd use hash[:second] instead? – unnamed_road Aug 24 '23 at 15:29
  • Are you referring to `hash.uniq(&:last)`? You can call `#select(&:last)` to remove all `nil` values. – David Aug 24 '23 at 15:56
  • 1
    `uniq` returns array, so you need to convert it to hash – mechnicov Aug 24 '23 at 17:47
1

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.

nitsas
  • 972
  • 7
  • 17
1
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}
mechnicov
  • 12,025
  • 4
  • 33
  • 56