Reputation: 172
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
Upvotes: 4
Views: 323
Reputation: 10074
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 >
Upvotes: -1
Reputation: 87386
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}
Upvotes: 6
Reputation: 18762
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
.
Upvotes: 1
Reputation: 8777
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 Array
s 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.
Upvotes: 4