Рубин:Как мне использовать символы для представления объектов в массиве?
Вопрос
У меня есть массив массивов, который выглядит примерно так:
fruits_and_calories = [
["apple", 100],
["banana", 200],
["kumquat", 225],
["orange", 90]
]
У меня также есть метод, который я хочу вызвать для каждого элемента массива:
fruits_and_calories.each do |f| eat(f[0], f[1])
Я бы очень хотел иметь возможность сказать что-то вроде:
fruits_and_calories.each do |f| eat(f[:name], f[:calories])
Есть ли способ, которым я могу выполнить это без необходимости изменять каждый элемент в массиве (например, путем перебора его и каким-либо образом добавляя символы)?Или, если это слишком сложно, есть ли лучшая альтернатива?
Решение
Лучший ответ - вообще не использовать массив, а использовать хэш:
fruits_and_calories = { :apple => 100,
:banana => 200,
:kumquat => 225,
:orange => 90}
fruits_and_calories.each do |name, calories|
eat(name, calories)
end
Другие советы
Вообще не меняя структуру данных, вы могли бы изменить аргументы блока, чтобы добиться того же самого:
fruits_and_calories.each do |name, calories| eat(name, calories); end
Это работает, потому что Ruby автоматически расширит внутренние массивы (["apple", 100] и т.д.) В список аргументов для блока ('do |name, calories| ...конец").Это трюк, который Ruby унаследовал от Lisp, известный как "деструктурирующие аргументы".
Ответ Песто (использовать хэш) хороший, но я думаю, что предпочел бы использовать 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)}
Это также поддается изменению eat
начиная с определения названия и калорийности и заканчивая приведением примера фрукта:
fruits.each {|f| eat(f)}
Есть ли какая-то причина для этого должен быть массивом как таковым?Это, кажется, кричит о том, что это хэш или класс для Фруктов.
Массив всегда индексируется числами, поэтому, насколько я знаю, используя стандартный массив, это невозможно.
Лично я бы просто предпочел использовать комментарий над кодом, чтобы намекнуть, что означают f [0] и f [1].
Но если вы одержимы идеей сделать это, я думаю, что некоторая утиная типизация в классе 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) }