2

Suppose I have a array, namely arr: [1, 2, 3, 4, 8, 8], and I want to find all max elements in this array:

arr.allmax # => [8, 8]

Is there a built-in method combinations to solve this? I don't like to monkey patch as I am doing now:

class Array
  def allmax
    max = self.max
    self.select { |e| e == max }
  end
end

Monkey patch is not a good idea, I could just do:

some_array.select { |e| e == some_array.max }

and it will work as allmax. Thanks for all answers and comments for inspirations.

sawa
  • 165,429
  • 45
  • 277
  • 381
Juanito Fatas
  • 9,419
  • 9
  • 46
  • 70

3 Answers3

1

Here is one way :

2.1.0 :006 > arr = [1, 2, 3, 4, 8, 8]
 => [1, 2, 3, 4, 8, 8] 
2.1.0 :007 > arr.group_by { |i| i }.max.last
 => [8, 8] 
2.1.0 :008 > 

Here is a method :-

  def all_max(arr)
    return [] if arr.empty?
    arr.group_by { |i| i }.max.last
  end
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • fails for empty array... – Uri Agassi May 13 '14 at 06:15
  • @UriAgassi I will wrap inside a method.. Give me a moment – Arup Rakshit May 13 '14 at 06:16
  • Great to see the `group_by`, my question is "do not monkey patch" the built-in `Array`, so plain `group_by` is okay, although it cannot handle the empty case. Thanks a lot, Arup! – Juanito Fatas May 13 '14 at 06:18
  • @juanitofatas Humm.. *monkey patch* not sounds good always.. But on empty array no need to do any operation. Just check for emptiness,if empty return it, or go for your other task to do.. I think this is a good way. – Arup Rakshit May 13 '14 at 06:20
1

Here's a fun way to do it.

arr.sort!.slice arr.index(arr[-1]) || 0..-1

Sort the array, then find the leftmost index of the array which matches the rightmost index of the array, and take the subslice that matches that range (or the range 0..-1 if the array is empty).

This one is kind of fun in that it requires no intermediate arrays, though it does mutate the input to achieve the one-liner.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
1

Another way:

def all_max(arr)
  return [] if arr.empty?
  mx = arr.max
  [mx] * arr.count { |e| e == mx }
end

all_max([1, 2, 3, 4, 8, 8]) 
  #=> [8, 8]

To construct the array in a single pass, you could do this:

arr.each_with_object([]) do |e,a|
  if a.empty?
    a << e
  else
    case e <=> a.first
    when 0 then a << e
    when 1 then a.replace([e])
    end
  end
end
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100