Я не говорю, что Array
-> |value,index|
и Hash
-> |key,value|
не безумен (см. Комментарий Горация Лоэба), но я говорю, что есть разумный способ ожидать такой договоренности.
Когда я имею дело с массивами, я сосредотачиваюсь на элементах массива (не на индексе, потому что индекс временный). Каждый метод имеет индекс, то есть каждый + индекс или | каждый, индекс | или |value,index|
. Это также согласуется с тем, что индекс рассматривается как необязательный аргумент, например | значение | эквивалентно значению | index = nil | что согласуется с | значением, индексом |.
Когда я имею дело с хэш, я часто более сосредоточен на клавишах , чем значения, и я , как правило , имеет дело с ключами и значениями в указанном порядке, либо key => value
или hash[key] = value
.
Если вы хотите печатать утку, то либо явно используйте определенный метод, как показал Брент Лонгборо, либо неявный метод, как показал maxhawkins.
Ruby - все о приспособлении языка к программисту, а не о программисте, приспособленном к языку. Вот почему есть так много способов. Есть так много способов думать о чем-то. В Ruby вы выбираете самый близкий, а остальная часть кода обычно получается очень аккуратно и лаконично.
Что касается первоначального вопроса: «Каков« правильный »способ перебора массива в Ruby?», Я думаю, основной способ (т.е. без мощного синтаксического сахара или объектно-ориентированной мощности) состоит в следующем:
for index in 0 ... array.size
puts "array[#{index}] = #{array[index].inspect}"
end
Но Ruby - это все о мощном синтаксическом сахаре и объектно-ориентированной мощности, но в любом случае здесь есть эквивалент для хэшей, и ключи можно упорядочить или нет:
for key in hash.keys.sort
puts "hash[#{key.inspect}] = #{hash[key].inspect}"
end
Итак, мой ответ: «Правильный способ перебора массива в Ruby зависит от вас (то есть программиста или команды программистов) и проекта». Лучший программист на Ruby делает лучший выбор (какой синтаксической мощности и / или какой объектно-ориентированный подход). Лучший программист на Ruby продолжает искать новые пути.
Теперь я хочу задать еще один вопрос: «Каков« правильный »способ перебора диапазона в Ruby в обратном направлении?»! (Этот вопрос, как я попал на эту страницу.)
Это приятно сделать (для форвардов):
(1..10).each{|i| puts "i=#{i}" }
но я не люблю делать (для задом наперед):
(1..10).to_a.reverse.each{|i| puts "i=#{i}" }
Ну, на самом деле я не против делать это слишком много, но когда я преподаю движение в обратном направлении, я хочу показать своим ученикам хорошую симметрию (т.е. с минимальной разницей, например, только добавление реверса или шаг -1, но без модифицируя что-нибудь еще). Вы можете сделать (для симметрии):
(a=*1..10).each{|i| puts "i=#{i}" }
и
(a=*1..10).reverse.each{|i| puts "i=#{i}" }
что я не очень люблю, но вы не можете сделать
(*1..10).each{|i| puts "i=#{i}" }
(*1..10).reverse.each{|i| puts "i=#{i}" }
#
(1..10).step(1){|i| puts "i=#{i}" }
(1..10).step(-1){|i| puts "i=#{i}" }
#
(1..10).each{|i| puts "i=#{i}" }
(10..1).each{|i| puts "i=#{i}" } # I don't want this though. It's dangerous
Вы могли бы в конечном итоге сделать
class Range
def each_reverse(&block)
self.to_a.reverse.each(&block)
end
end
но я хочу преподавать чистый Ruby, а не объектно-ориентированные подходы (только пока). Я хотел бы повторить в обратном направлении:
- без создания массива (рассмотрим 0..1000000000)
- работает для любого диапазона (например, строки, а не только целые числа)
- без использования какой-либо дополнительной объектно-ориентированной мощности (т.е. без модификации класса)
Я считаю, что это невозможно без определения pred
метода, что означает изменение класса Range для его использования. Если вы можете сделать это, пожалуйста, дайте мне знать, в противном случае подтверждение невозможности будет приветствоваться, хотя это будет разочаровывать. Возможно, Ruby 1.9 решает эту проблему.
(Спасибо за ваше время на чтение этого.)
array#each_with_index
использует,|value, key|
потому что имя метода подразумевает порядок, тогда как порядок, используемый дляhash#each
имитацииhash[key] = value
синтаксиса?