2016-05-15 2 views
2

Array#max_by возвращает только одно значение, но я хочу иметь все значения, которые имеют максимальное значение.Как использовать & proc аргумент внутри метода

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}] 

Этот код работает отлично, и я хочу, чтобы добавить его в Array класса.

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

Как получить доступ к аргументу &proc?

+1

более простой способ решить проблему здесь: HTTP://stackoverflow.com/questions/22115956. – sawa

+0

BTW, '& block' является более распространенным именем для этой переменной. – Stefan

+0

Я согласен с @Stefan. Использование имени 'proc' вводит в заблуждение, потому что можно ожидать, что он будет содержать экземпляр lambda или non-lambda Proc. –

ответ

2

Используйте proc в блоке передается select, вызвав его с 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}] 

или с yield, что дает одинаковые результаты:

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

Хотя proc.call немного больше, чем yield , Я предпочитаю его в этом случае, потому что он дает понять, что тот же блок используется в двух местах в методе, и потому что странно использовать как i mclicit block pass yield и явный переход &proc в тот же метод.

+0

Вы также можете использовать 'yield (h)' вместо 'proc.call (h)' – Stefan

+0

Добавлено, спасибо. Существует также «ProC# yield», но это просто сбивает с толку. –

+1

Вы думаете, что 'ProC# yield' запутан? Вы также можете вызывать proc с помощью '(proc === h)' (и с помощью '[]', как упоминалось в OP, и с помощью proc (h) 'с личным, но все-таки-с-нами"). , –

1

@DaveSchweisguth предлагает отличную реализацию с использованием select, как вы просили. Другой способ достижения того же результата является использование group_by, как это:

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

или обезьяна-заплата в массив как:

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

Это не то, что задал ОП. Но это то же самое, что и принятый ответ на этот вопрос: http://stackoverflow.com/questions/22115956. – sawa

Смежные вопросы