The least of them: minimum (and maximum) array values (plural!)
Every once in a while, I find myself wanting to do things like this:
017:0> %w(one two four six).find_all_min {|w| w.length}
["one", "two", "six"]
018:0> [3, 2, 1, 3, 1, 1, 3, 2].find_all_max
[3, 3, 3]
I want the values from an array that are the most (or least) of some property. And the array and property are arbitrary. Always.
I know I could just do something like:
009:0> array = %w(1 2 3 3)
["1", "2", "3", "3"]
010:0> max = array.map {|x| x.to_i}.max
3
011:0> array.find_all {|x| x.to_i == max}
["3", "3"]
But it looks clunky to me. What I really want are methods to do that for me, and I want methods that are a little more complicated, and generated via module_eval… and using a Proc. What I want, in short, is this:
module Enumerable [['min','-1'], ['max','1']].each do |name, comparator| module_eval %{ def find_all_#{name} block = Proc.new do |object| block_given? ? yield(object) : object end self.inject([]) do |result, element| if result.empty? result << element else case block[element] <=> block[result.first] when 0 result << element when #{comparator} [element] else result end end end end } end end
It’s not the best way to handle this situation, but I’m on a metaprogramming diet, because that’s something I don’t have enough practice in. So I’m doing it more than I need to. I’m trying to get a feel of when a Proc is called for (har har). Given the way I’m doing the inject, I feel that the Proc is a good move. Maybe I’m wrong.