Ruby: Come uso i simboli per rappresentare le cose in un array?
Domanda
Ho una serie di array che assomiglia a questo:
fruits_and_calories = [
["apple", 100],
["banana", 200],
["kumquat", 225],
["orange", 90]
]
Ho anche un metodo che voglio invocare su ogni elemento dell'array:
fruits_and_calories.each do |f| eat(f[0], f[1])
Mi piacerebbe davvero poter dire qualcosa del tipo:
fruits_and_calories.each do |f| eat(f[:name], f[:calories])
Esiste un modo per riuscirci senza dover modificare ogni elemento dell'array (ad esempio, scorrendo attraverso di esso e aggiungendo in qualche modo i simboli)? Oppure, se è troppo difficile, esiste un'alternativa migliore?
Soluzione
La risposta migliore non è affatto usare un array, ma usare un hash:
fruits_and_calories = { :apple => 100,
:banana => 200,
:kumquat => 225,
:orange => 90}
fruits_and_calories.each do |name, calories|
eat(name, calories)
end
Altri suggerimenti
Senza modificare affatto la struttura dei dati, è possibile modificare gli argomenti del blocco per ottenere la stessa cosa:
fruits_and_calories.each do |name, calories| eat(name, calories); end
Funziona perché Ruby espande automaticamente le matrici interne ([" apple " ;, 100], ecc.) nell'elenco degli argomenti per il blocco ('do | name, calories | ... end'). Questo è un trucco che Ruby ha ereditato da Lisp, noto come "argomenti destrutturanti".
La risposta di Pesto (usa un hash) è buona, ma penso che preferirei usare 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)}
Questo si presta anche a cambiare mangia
dall'assumere sia il nome che le calorie, a prendere un'istanza di frutta:
fruits.each {|f| eat(f)}
C'è qualche motivo per cui deve essere di per sé un array? Sembra che si tratti di un hash o di una lezione per Fruit.
Un array è sempre indicizzato da numeri, quindi per quanto ne so usare l'array standard non è possibile.
Personalmente opterei per l'utilizzo di un commento sopra il codice per suggerire che cosa f [0] e f [1] rappresenta.
Ma se sei intenzionato a farlo, immagino che alcuni tipi di anatre sui lavori della classe Array:
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) }