2

For example, if I have the hash {"a" => 1, "b" => 2, "c" => 1}, I want ["a", "c"].

I can do hash.min_by{|k,v| v}, but that only returns the first match ("a"=>1).

How do I get it to recognize duplicates and return {"a"=> 1, "c"=> 1}?

Ry-
  • 218,210
  • 55
  • 464
  • 476
Chris
  • 1,101
  • 2
  • 9
  • 14

3 Answers3

7

That operation is a bit unusual for a hash, so it’s not very neat:

min_value = hash.values.min
min_pairs = hash.select { |k, v| v == min_value }
Ry-
  • 218,210
  • 55
  • 464
  • 476
5
{"a" => 1, "b" => 2, "c" => 1}.group_by(&:last).min.last.map(&:first)
# => ["a", "c"]

or

{"a" => 1, "b" => 2, "c" => 1}.group_by(&:last).min.last.to_h.keys
# => ["a", "c"]
Ry-
  • 218,210
  • 55
  • 464
  • 476
sawa
  • 165,429
  • 45
  • 277
  • 381
  • 1
    ...or `h.group_by(&:last).min.last.to_h #=> {"a"=>1, "c"=>1}` to provide the result in the form requested. Readers: note that `min` applies to key-value pairs (two-element arrays) of the hash produced by `group_by`. – Cary Swoveland Feb 01 '17 at 06:39
1

You can write FORTRAN in any language! :)

It has the advantage of only requiring 1 pass :

hash = {"a" => 1, "b" => 2, "c" => 1}

min = Float::INFINITY
values_for_min = []

hash.each do |key, value|
  case value <=> min
  when 0
    values_for_min << key
  when -1
    min = value
    values_for_min = [key]
  end
end

p min
#=> 1
p values_for_min
#=> ["a", "c"]
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124