Ruby: Como faço para usar símbolos para representar as coisas de uma matriz?
Pergunta
Eu tenho uma matriz de matrizes que se parece com isso:
fruits_and_calories = [
["apple", 100],
["banana", 200],
["kumquat", 225],
["orange", 90]
]
Eu também tenho um método que deseja chamar em cada elemento da matriz:
fruits_and_calories.each do |f| eat(f[0], f[1])
Eu realmente gostaria de ser capaz de dizer algo como:
fruits_and_calories.each do |f| eat(f[:name], f[:calories])
Existe uma maneira que eu posso conseguir isso sem ter que alterar cada item na matriz (por exemplo, por iteração através dela e de alguma forma adicionando os símbolos in)? Ou, se isso é muito difícil, há uma alternativa melhor?
Solução
A melhor resposta é não usar uma matriz em tudo, mas usar um Hash:
fruits_and_calories = { :apple => 100,
:banana => 200,
:kumquat => 225,
:orange => 90}
fruits_and_calories.each do |name, calories|
eat(name, calories)
end
Outras dicas
Sem mudar a estrutura de dados em tudo, você poderia alterar os argumentos bloco para alcançar a mesma coisa:
fruits_and_calories.each do |name, calories| eat(name, calories); end
Isso funciona porque Ruby vai auto-expandem as matrizes internas ([ "alimento", 100], etc) para a lista de argumentos para o bloco ( 'fazer | nome, calorias | ... end'). Este é um truque que Ruby herdou de Lisp, conhecido como 'argumentos desestruturação'.
A resposta de Pesto (use um hash) é uma boa, mas eu acho que eu prefiro usar uma estrutura.
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)}
Isto também se presta a mudança eat
de tomar tanto o nome e calorias, para tomar um exemplo de frutas:
fruits.each {|f| eat(f)}
Existe alguma razão ele deve ser um array, por si só? Isso parece clamar a ser um hash ou uma classe das Frutas.
Uma matriz é sempre indexados por números, por isso, tanto quanto eu sei usando a matriz padrão que não é possível.
Pessoalmente, eu tinha acabado de opt para usar um comentário acima do código de sugerir o que f [0] e f [1] representa.
Mas se você é o inferno dobrado em fazer isso eu acho que alguma pato-digitando sobre as obras da 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) }