Автоматический счетчик в Ruby для каждого?

134

Я хочу использовать для каждого и счетчик:

i=0
for blah in blahs
    puts i.to_s + " " + blah
    i+=1
end

Есть ли лучший способ сделать это?

Примечание: я не знаю blahs, массив это или хеш, но необходимость сделать blahs[i]это не сделает его более сексуальным. Также я хотел бы знать, как писать i++на Ruby.


Технически, ответ Мэтта и Сквиги пришел первым, но я даю наилучший ответ на парадоджу, поэтому немного расскажу о SO. Также в его ответе была записка о версиях, которая по-прежнему актуальна (пока моя Ubuntu 8.04 использует Ruby 1.8.6).


Надо было использовать puts "#{i} #{blah}"что-то более лаконичное.

Дэн Розенстарк
источник
В Ruby нет оператора приращения. N + = 1, который вы записали, является ближайшим аналогом. Это должен быть синтаксический сахар для n + = 1, что само по себе является сокращением для n = n + 1. Идея ++ была отвергнута, потому что она скрывает тот факт, что вы переназначаете переменную. rubyurl.com/Dsb1
Чак
Ницца! Спасибо Чак. Я был вынужден изучать ++ i и i ++ на Java, поэтому я просто думал, что это всегда будет.
Дэн Розенстарк

Ответы:

190

Как уже говорили люди, вы можете использовать

each_with_index

но если вам нужны индексы с итератором, отличным от «каждого» (например, если вы хотите отобразить с помощью индекса или чего-то подобного), вы можете объединить перечислители с помощью метода each_with_index или просто использовать with_index:

blahs.each_with_index.map { |blah, index| something(blah, index)}

blahs.map.with_index { |blah, index| something(blah, index) }

Это то, что вы можете сделать из ruby ​​1.8.7 и 1.9.

paradoja
источник
1
Стоит отметить, что это новое в 1.9.
Зак Лэнгли
1
Хорошо подмечено. На самом деле, это тоже в 1.8.7, но это то, что стоит добавить.
парадоя
почему я на Ruby 1.8.6, если я только что установил все это на Ubuntu? 1.8.7 экспериментально / бета?
Дэн Розенстарк
Какой Ubuntu вы используете? В Intrepid есть 1.8.7. Это последняя стабильная версия ( ruby-lang.org/en/downloads ). Вы можете, однако, monkeypatch рубин 1.8.6 иметь такое же поведение (см strictlyuntyped.com/2008/09/ruby-187s-enumerator-class.html ).
парадоя
3
Я устал от дистрибутива, поэтому я начал использовать rvm для управления установкой Ruby в Ubuntu и Linux Mint.
Жестянщик
55
[:a, :b, :c].each_with_index do |item, i|
  puts "index: #{i}, item: #{item}"
end

Вы не можете сделать это с помощью. Я обычно люблю более декларативный звонок каждому лично в любом случае. Отчасти потому, что легко переходить в другие формы, когда вы достигаете предела синтаксиса for.

Алекс Уэйн
источник
Хорошо, я вижу смысл в ограничениях синтаксиса for. Я должен привыкнуть к блокам с несколькими параметрами.
Дэн Розенстарк
11

Да, это collection.eachделать циклы, а затем each_with_indexполучать индекс.

Вы, вероятно, должны прочитать книгу по Ruby, потому что это фундаментальный Ruby, и если вы его не знаете, у вас будут большие проблемы (попробуйте: http://poignantguide.net/ruby/ ).

Взято из исходного кода Ruby:

 hash = Hash.new
 %w(cat dog wombat).each_with_index {|item, index|
   hash[item] = index
 }
 hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
Мэтт Рогиш
источник
Нет проблем, рад помочь. Не значит быть «подлым» в отношении блока .each - это фундаментальные рубиновые конструкции, и их изучение на лету будет действительно, очень болезненным. :) Лучше всего укусить пулю и потратить несколько часов на чтение!
Мэтт Рогиш
6

Если у вас нет новой версии each_with_index, вы можете использовать zipметод для сопряжения индексов с элементами:

blahs = %w{one two three four five}
puts (1..blahs.length).zip(blahs).map{|pair|'%s %s' % pair}

который производит:

1 one
2 two
3 three
4 four
5 five
Джордж
источник
1
Где я могу найти этот код из вашего ответа '%s %s' % [1, "two"]в документации по Ruby? Спасибо за вашу помощь и за сохранение вертикального пространства, используя одну строку для архивирования и картирования.
Дэн Розенстарк
1
В этом контексте оператор% -sign является методом класса String. Вы можете прочитать об этом на ruby-doc.org/core/classes/String.html#M000770 . Или вы можете набрать ri String #% в командной строке. Или вы можете набрать ri%, чтобы увидеть все документированные классы, которые его распознают, например, более знакомое значение в ri Fixnum #%.
Джордж
4

Что касается вашего вопроса о том, что делать i++, ну, вы не можете сделать это в Ruby. Ваше i += 1заявление именно так и должно быть.

папа
источник
1

Если blahsэто класс, который смешивается в Enumerable, вы должны быть в состоянии сделать это:

blahs.each_with_index do |blah, i|
  puts("#{i} #{blah}")
end
Рой Парди
источник
1

Если вы хотите получить индекс ruby ​​для каждого, то вы можете использовать

.each_with_index

Вот пример, чтобы показать, как .each_with_indexработает:

range = ('a'..'z').to_a
length = range.length - 1
range.each_with_index do |letter, index|
    print letter + " "
    if index == length
        puts "You are at last item"
    end
end

Это напечатает:

a b c d e f g h i j k l m n o p q r s t u v w x y z You are at last item
Ильяс Карим
источник