Я не говорю, что 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 решает эту проблему.
(Спасибо, что уделили мне время на чтение.)