Ruby: ¿Cómo uso los símbolos para representar cosas en una matriz?
Pregunta
Tengo una serie de matrices que se parecen a esto:
fruits_and_calories = [
["apple", 100],
["banana", 200],
["kumquat", 225],
["orange", 90]
]
También tengo un método que quiero invocar en cada elemento de la matriz:
fruits_and_calories.each do |f| eat(f[0], f[1])
Realmente me gustaría poder decir algo como:
fruits_and_calories.each do |f| eat(f[:name], f[:calories])
¿Hay alguna forma de poder hacer esto sin tener que cambiar cada elemento de la matriz (por ejemplo, al iterar a través de él y agregar los símbolos de alguna manera)? O, si eso es demasiado difícil, ¿hay alguna alternativa mejor?
Solución
La mejor respuesta es no usar una matriz en absoluto, sino usar un hash:
fruits_and_calories = { :apple => 100,
:banana => 200,
:kumquat => 225,
:orange => 90}
fruits_and_calories.each do |name, calories|
eat(name, calories)
end
Otros consejos
Sin cambiar la estructura de datos, podría cambiar los argumentos de bloque para lograr lo mismo:
fruits_and_calories.each do |name, calories| eat(name, calories); end
Esto funciona porque Ruby expandirá automáticamente las matrices internas ([" apple " ;, 100], etc.) en la lista de argumentos para el bloque ('do | name, calorías | ... end'). Este es un truco que Ruby heredó de Lisp, conocido como 'desestructuración de argumentos'.
La respuesta de Pesto (usar un hash) es buena, pero creo que preferiría usar un Struct.
Fruit = Struct.new(:name, :calories)
fruits = [
Fruit.new("apple", 100),
Fruit.new("banana", 200),
Fruit.new("kumquat", 225),
Fruit.new("orange", 90)
]
fruits.each {|f| eat(f.name, f.calories)}
Esto también se presta al cambio de eat
de tomar tanto el nombre como las calorías, a tomar una instancia de fruta:
fruits.each {|f| eat(f)}
¿Hay alguna razón por la que debe ser una matriz, per se? Eso parece ser un hash, o una clase para Fruit.
Una matriz siempre se indexa por números, por lo que sé que usar la matriz estándar no es posible.
Personalmente, solo optaría por usar un comentario sobre el código para sugerir qué significan f [0] yf [1].
Pero si estás empeñado en hacerlo, supongo que algunos tipos de pato en la clase Array funcionan:
class Array
def name ; self[0] ; end
def calories ; self[1] ; end
end
# then call it with:
fruits_and_calories.each {|f| eat(f.name, f.calories) }