Ruby: Как я могу использовать символы для представления вещей в массиве? - PullRequest
1 голос
/ 30 апреля 2009

У меня есть массив массивов, который выглядит следующим образом:

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])

Есть ли способ, которым я могу осуществить это, не меняя каждый элемент в массиве (например, перебирая его и добавляя символы)? Или, если это слишком сложно, есть ли лучшая альтернатива?

Ответы [ 5 ]

9 голосов
/ 30 апреля 2009

Лучший ответ - не использовать массив вообще, а использовать хэш:

fruits_and_calories = { :apple => 100,
                        :banana => 200,
                        :kumquat => 225,
                        :orange => 90}
fruits_and_calories.each do |name, calories| 
  eat(name, calories)
end
7 голосов
/ 30 апреля 2009

Даже не меняя структуру данных, вы можете изменить аргументы блока для достижения того же:

fruits_and_calories.each  do |name, calories|  eat(name, calories);  end

Это работает, потому что Ruby автоматически развернет внутренние массивы (["apple", 100] и т. Д.) В список аргументов для блока ('do | name, calories | ... end'). Это уловка, унаследованная Ruby от Lisp, известная как «аргументы деструктурирования».

4 голосов
/ 30 апреля 2009

Ответ Песто (используйте хеш) хороший, но я думаю, что предпочел бы использовать 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)}
0 голосов
/ 30 апреля 2009

Есть ли какая-то причина, по которой должен быть массивом как таковым? Кажется, это хэш или класс для Fruit.

0 голосов
/ 30 апреля 2009

Массив всегда индексируется по номерам, поэтому, насколько я знаю, используя стандартный массив, это невозможно.

Лично я бы предпочел использовать комментарий над кодом, чтобы намекнуть, что означают 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) }
...