Max value within array of objects
Asked Answered
C

2

5

I'm new in ruby. I'm trying to do the following but haven't succeeded.

I've got an array of objects, let's call it objs. Each object has multiple properties, one of those is a variable that holds a number, let's call it val1. I wanna iterate through the array of objects and determine the max value of val1 through all the objects.

I've tried the following:

def init(objs)
  @objs = objs
  @max = 0
  cal_max
end

def cal_max

  @max = @objs.find { |obj| obj.val1 >= max }

  # also tried
  @objs.each { |obj| @max = obj.val1 if obj.val1 >= @max }

end

As I said, I'm just learning about blocks.

Any suggestion is welcome.

Thanks

Cementation answered 17/9, 2016 at 1:54 Comment(0)
D
6

Let's say you have set up the following model:

class SomeObject
  attr_accessor :prop1, :prop2, :val1

  def initialize(prop1, prop2, val1)
    @prop1 = prop1
    @prop2 = prop2
    @val1  = val1
  end
end

#define your objects from the class above
david  = SomeObject.new('David',  'Peters', 23)
steven = SomeObject.new('Steven', 'Peters', 26)
john   = SomeObject.new('John',   'Peters', 33)

#define an array of the above objects
array = [david, steven, john]

Then use max_by by passing the condition into its block as follows to determine the object with the max val1 value. Finally call val1 to get the value of the max object.

array.max_by {|e| e.val1 }.val1 #=> 33

You may also consider using hashes (negating the need to define a new class), like so:

david  = {f_name: 'David',  s_name: 'Peters', age: 23}
steven = {f_name: 'Steven', s_name: 'Peters', age: 26}
john   = {f_name: 'John',   s_name: 'Peters', age: 33}

array = [david, steven, john]
array.max_by { |hash| hash[:age] }[:age] #=> 33
Diapason answered 17/9, 2016 at 2:26 Comment(4)
Worked like charm. Question, does array.max_by {|e| e.val1 } return an 'e' object? that's why we have to access it with .val1 at the end? array.max_by {|e| e.val1 }.val1Cementation
@Cementation Yes, although it would be incorrect to describe it as an 'e' object. array.max_by {|e| e.val1 } returns a SomeObject object. We call the val1 method at the end to determine its val1 property. We could also call prop1 if we wanted the first name for example. Hope this helps.Diapason
Yes it does, a lot. ThanksCementation
@Sebastian, perhaps consider using hashes? I've updated my answer.Diapason
B
5
@objs.map(&:val1).max

That will invoke the method on each object, and create a new array of the results, and then find the max value. This is shorthand for:

@objs.map{ |o| o.val1 }.max

Alternatively, you can select the object with the largest value, and then operate on it (as properly recomended by Cary Swoveland below):

@objs.max_by(&:val1).val1
Biannulate answered 17/9, 2016 at 2:11 Comment(2)
...or @objs.max_by(&:val1).val1.Bianco
@CarySwoveland You and your newfangled methods!Biannulate

© 2022 - 2024 — McMap. All rights reserved.