ironsand
ironsand

Reputation: 15141

How to use &proc argument inside method

Array#max_by returns only a single value, but I want to have all values that have the max value.

hashes = [{a: 1, b:2}, {a:2, b:3}, {a:1, b:3}]
max = hashes.map{|h| h[:b]}.max
hashes.select{|h| h[:b] == max}
# => [{a: 2, b: 3}, {a: 1, b: 3}]

This code works fine, and I want to add it to Array class.

class Array
  def max_values_by(&proc)
    max = map(&proc).max
    # I don't know how to use `select` here.
  end
end

How to access the value of the &proc argument?

Upvotes: 2

Views: 172

Answers (2)

Dave Schweisguth
Dave Schweisguth

Reputation: 37607

Use the proc in the block passed to select by calling it with call:

class Array
  def max_values_by(&proc)
    max = map(&proc).max
    select { |h| proc.call(h) == max }
  end
end
hashes.max_values_by { |h| h[:b] }
=> [{a: 2, b: 3}, {a: 1, b: 3}]

or with yield, which gives identical results:

def max_values_by(&proc)
  max = map(&proc).max
  select { |h| yield(h) == max }
end

Although proc.call is a little longer than yield, I prefer it in this case because it makes it clearer that the same block is being used in two places in the method, and because it's weird to use both the implicit block passing of yield and the explicit passing of &proc in the same method.

Upvotes: 2

user12341234
user12341234

Reputation: 7193

@DaveSchweisguth suggests a great implementation using select, like you requested. Another way of achieving the same result is by using group_by, like this:

>> hashes.group_by{|h| h[:b]}.max.last
=> [{:a=>2, :b=>3}, {:a=>1, :b=>3}]

or monkey-patched into Array as:

class Array
  def max_values_by(&proc)
    group_by(&proc).max.last
  end
end

Upvotes: 1

Related Questions