4

If I have an array of variables in Ruby:

a = 4
b = 7
c = 1

array = [a, b, c]

How can I get access to the name of the variable that has the highest value? (In this example b) I want to retrieve a reference to the element with the highest value, to be able to later manipulate it:

b += 10 

I tried array.max but that just returns the max value 7

infused
  • 24,000
  • 13
  • 68
  • 78
Mushy
  • 172
  • 1
  • 2
  • 13

4 Answers4

6

When you build an array by writing array = [a, b, c], the spots in the array do not retain any kind of association with the variables named a, b, and c, so you there is no way to do exactly what you are talking about. Those variables can change without affecting the array.

You could change the way you are storing your data in order to make this possible, but without knowing what data you are storing it is hard to recommend a good way to do it. You could consider storing your data inside a hash instead of in loose variables and an array:

hash = { a: 4, b: 7, c: 1}
David Grayson
  • 84,103
  • 24
  • 152
  • 189
4

Ruby does not support passing objects by reference, which is essentially what you are trying to do. When you call array.max, you are passed a copy of the Fixnum 7, and assignment and modification will be applied to this copy.

That is, you can not store a reference to this Array element, and modify it later. You can modify the maximum value on the spot, however, using:

array[array.index(array.max)] = array.max + 10
#=> 17

array
#=> [4, 17, 1]

Note that when there are duplicate values in the Array, array.index(array.max) will return the index of the first one.

Storing the index for later use is not a solid solution, since, while Arrays in Ruby are ordered, the Array or its elements can be modified between the point you retrieve the index, and the point where you decide to change the corresponding value.


Another answer suggests there's a hack to mimic pass-by-reference behaviour, but in doing this, you're working against the intention of the language, and it could lead to a lot of pain down the line.

Community
  • 1
  • 1
Drenmi
  • 8,492
  • 4
  • 42
  • 51
  • 1
    Objects like hashes and arrays are passed around by reference all the time. I think you meant to say something else, like variables cannot be passed by reference. – David Grayson Dec 22 '15 at 16:32
1

If you are trying to manipulate the maximum of three values, then, you are better off doing something like this:

array.max + 10  # or any other manipulation for that matter.

If you are asking what you are asking for academic purposes, then, you could use Ruby's Binding to inspect values of local variables.

a = 4
b = 7
c = 1

array = [a, b, c]

# Select variable whose value matches with maximum of three elements
# Variable's name as symbol is obtained by this process
var = binding.send(:local_variables).select do |i| 
    array.max.eql? binding.local_variable_get(i)
end.first
#=> :b

# Update value of variable using symbol representing  its name
binding.local_variable_set(var, binding.local_variable_get(var) + 10)

puts b
#=> 17

You could also use Binding#eval to manipulate the variable, for e.g.:

binding.eval("#{var.to_s} += 10")
#=> 17

Note that we need to use var.to_s as var contains a symbol, and we need to convert it to string to get variable name string that can be used in eval.

Wand Maker
  • 18,476
  • 8
  • 53
  • 87
-1

You can use Array#index for this..

1.9.3-p484 :008 > max_elem = array.index(array.max)
 => 1
1.9.3-p484 :009 > array[max_elem] = array[max_elem] + 10
 => 11
1.9.3-p484 :010 > array
 => [4, 17, 1]
1.9.3-p484 :011 >
ptierno
  • 9,534
  • 2
  • 23
  • 35