PHP, несмотря ни на что, довольно хорош в этом смысле. Нет никакой разницы между массивом и хешем (возможно, я наивен, но это, очевидно, мне подходит), и для итерации либо вы просто делаете
foreach (array/hash as $key => $value)
В Ruby есть множество способов сделать это:
array.length.times do |i|
end
array.each
array.each_index
for i in array
Хэши имеют больше смысла, так как я просто всегда использую
hash.each do |key, value|
Почему я не могу сделать это для массивов? Если я хочу запомнить только один метод, я думаю, что я могу использовать each_index
(так как он делает доступным и индекс, и значение), но раздражает необходимость делать это array[index]
вместо простого value
.
Ах да, я забыл о array.each_with_index
. Однако этот отстой, потому что он идет |value, key|
и hash.each
уходит |key, value|
! Разве это не безумие?
array#each_with_index
использует,|value, key|
потому что имя метода подразумевает порядок, тогда как порядок, используемый дляhash#each
имитацииhash[key] = value
синтаксиса?Ответы:
Это будет перебирать все элементы:
Печать:
Это будет перебирать все элементы, давая вам значение и индекс:
Печать:
Я не совсем уверен по вашему вопросу, какой вы ищете.
источник
Я думаю, что нет единственно верного пути. Существует много разных способов итерации, и у каждого своя ниша.
each
достаточно для многих случаев, так как меня не очень интересуют индексы.each_ with _index
действует как Hash # each - вы получаете значение и индекс.each_index
- только индексы. Я не пользуюсь этим часто. Эквивалент "length.times".map
это еще один способ итерации, полезный, когда вы хотите преобразовать один массив в другой.select
итератор, который нужно использовать, когда вы хотите выбрать подмножествоinject
полезен для генерации сумм или продуктов или для сбора одного результата.Может показаться, что многое нужно запомнить, но не волнуйтесь, вы можете обойтись, не зная их всех. Но когда вы начнете изучать и использовать различные методы, ваш код будет становиться все яснее и яснее, и вы будете на пути к мастерству в Ruby.
источник
Я не говорю, что
Array
->|value,index|
иHash
->|key,value|
не безумен (см. Комментарий Горация Лоэба), но я говорю, что есть разумный способ ожидать такой договоренности.Когда я имею дело с массивами, я сосредотачиваюсь на элементах массива (не на индексе, потому что индекс временный). Каждый метод имеет индекс, то есть каждый + индекс или | каждый, индекс | или
|value,index|
. Это также согласуется с тем, что индекс рассматривается как необязательный аргумент, например | значение | эквивалентно значению | index = nil | что согласуется с | значением, индексом |.Когда я имею дело с хэш, я часто более сосредоточен на клавишах , чем значения, и я , как правило , имеет дело с ключами и значениями в указанном порядке, либо
key => value
илиhash[key] = value
.Если вы хотите печатать утку, то либо явно используйте определенный метод, как показал Брент Лонгборо, либо неявный метод, как показал maxhawkins.
Ruby - все о приспособлении языка к программисту, а не о программисте, приспособленном к языку. Вот почему есть так много способов. Есть так много способов думать о чем-то. В Ruby вы выбираете самый близкий, а остальная часть кода обычно получается очень аккуратно и лаконично.
Что касается первоначального вопроса: «Каков« правильный »способ перебора массива в Ruby?», Я думаю, основной способ (т.е. без мощного синтаксического сахара или объектно-ориентированной мощности) состоит в следующем:
Но Ruby - это все о мощном синтаксическом сахаре и объектно-ориентированной мощности, но в любом случае здесь есть эквивалент для хэшей, и ключи можно упорядочить или нет:
Итак, мой ответ: «Правильный способ перебора массива в Ruby зависит от вас (то есть программиста или команды программистов) и проекта». Лучший программист на Ruby делает лучший выбор (какой синтаксической мощности и / или какой объектно-ориентированный подход). Лучший программист на Ruby продолжает искать новые пути.
Теперь я хочу задать еще один вопрос: «Каков« правильный »способ перебора диапазона в Ruby в обратном направлении?»! (Этот вопрос, как я попал на эту страницу.)
Это приятно сделать (для форвардов):
но я не люблю делать (для задом наперед):
Ну, на самом деле я не против делать это слишком много, но когда я преподаю движение в обратном направлении, я хочу показать своим ученикам хорошую симметрию (т.е. с минимальной разницей, например, только добавление реверса или шаг -1, но без модифицируя что-нибудь еще). Вы можете сделать (для симметрии):
и
что я не очень люблю, но вы не можете сделать
Вы могли бы в конечном итоге сделать
но я хочу преподавать чистый Ruby, а не объектно-ориентированные подходы (только пока). Я хотел бы повторить в обратном направлении:
Я считаю, что это невозможно без определения
pred
метода, что означает изменение класса Range для его использования. Если вы можете сделать это, пожалуйста, дайте мне знать, в противном случае подтверждение невозможности будет приветствоваться, хотя это будет разочаровывать. Возможно, Ruby 1.9 решает эту проблему.(Спасибо за ваше время на чтение этого.)
источник
1.upto(10) do |i| puts i end
и10.downto(1) do puts i end
вроде дает симметрию, которую вы хотели. Надеюсь, это поможет. Не уверен, что это будет работать для строк и тому подобное.[*1..10].each{|i| puts "i=#{i}" }
.Используйте each_with_index, когда вам нужны оба.
источник
Другие ответы просто хороши, но я хотел бы отметить еще одну второстепенную вещь: массивы упорядочены, а хэши не в 1.8. (В Ruby 1.9 хэши упорядочены по порядку вставки ключей.) Поэтому до версии 1.9 не имеет смысла перебирать хэш так же, как и массивы, которые всегда имели определенный порядок. Я не знаю, каков порядок по умолчанию для ассоциативных массивов PHP (по-видимому, мой Google Fu тоже недостаточно силен, чтобы это выяснить), но я не знаю, как можно рассматривать обычные массивы PHP и ассоциативные массивы PHP для быть «одинаковым» в этом контексте, так как порядок ассоциативных массивов кажется неопределенным.
Таким образом, путь Ruby кажется мне более понятным и интуитивно понятным. :)
источник
Попытка сделать то же самое последовательно с массивами и хешами может быть просто запахом кода, но, рискуя тем, что меня заклеймят как ядовитого наполовину обезьяны-патчера, если вы ищете последовательное поведение, это бы сработало ?:
источник
Вот четыре варианта, перечисленные в вашем вопросе, упорядоченные по свободе контроля. Вы можете использовать другой в зависимости от того, что вам нужно.
Просто пройдите значения:
Просто пройдите индексы:
Пройдите через индексы + индексную переменную:
Счетчик цикла управления + индексная переменная:
источник
Я пытался создать меню (в Camping и Markaby ), используя хэш.
Каждый элемент имеет 2 элемента: метку меню и URL , поэтому хэш выглядел правильным, но URL '/' для 'Home' всегда появлялся последним (как и следовало ожидать для хэша), поэтому пункты меню отображались неправильно порядок.
Использование массива с
each_slice
делает работу:Добавление дополнительных значений для каждого элемента меню (например, имя CSS- идентификатора ) просто означает увеличение значения среза. Таким образом, как хэш, но с группами, состоящими из любого количества элементов. Отлично.
Так что это просто сказать спасибо за непреднамеренный намек на решение!
Очевидно, но стоит заявить: я предлагаю проверить, делится ли длина массива на значение среза.
источник
Если вы используете перечисляемый миксин (как это делает Rails), вы можете сделать что-то похожее на приведенный фрагмент php. Просто используйте метод each_slice и сгладьте хеш.
Требуется меньше исправлений обезьян.
Однако это вызывает проблемы, когда у вас есть рекурсивный массив или хэш со значениями массива. В ruby 1.9 эта проблема решается с помощью параметра для метода flatten, который указывает, насколько глубокой должна быть рекурсия.
Что касается вопроса, является ли это запахом кода, я не уверен. Обычно, когда мне нужно наклониться назад, чтобы перебрать что-то, я отступаю и понимаю, что нападаю на проблему неправильно.
источник
Правильный путь - это тот, который вам наиболее удобен и который делает то, что вы хотите. В программировании редко бывает один «правильный» способ делать вещи, чаще всего есть несколько способов выбора.
Если вас устраивает определенный способ действий, просто делайте это, если он не работает - тогда пришло время найти лучший путь.
источник
В Ruby 2.1 метод each_with_index удален. Вместо этого вы можете использовать each_index
Пример:
производит:
источник
each_with_index
не указана в документации, потому что она предоставляетсяEnumerable
модулем.Использование одного и того же метода для перебора как массивов, так и хэшей имеет смысл, например, для обработки вложенных структур хеш-массивов, часто возникающих в результате синтаксического анализа, чтения файлов JSON и т. Д.
Один умный способ, который еще не был упомянут, состоит в том, как это сделать в библиотеке Ruby Facets стандартных расширений библиотеки. От сюда :
Уже
Hash#each_pair
есть псевдонимHash#each
. Таким образом, после этого патча мы также имеемArray#each_pair
и можем использовать его взаимозаменяемо для перебора как хешей, так и массивов. Это исправляет наблюдаемое безумие OP,Array#each_with_index
у которого аргументы блока обращены по сравнению сHash#each
. Пример использования:источник