цикл по остальной части перечислителя в Ruby - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть перечислитель в середине некоторой последовательности:

enum = (1..9).each
first = enum.next
second = enum.next

Теперь я хочу перебрать оставшуюся часть последовательности (3..9 числа). Но кажущееся очевидным решение (которое работает, например, в python), перезапустите с начала последовательности вместо третьего элемента:

for item in enum
    puts item
end
# prints 1..9 instead of 3..9

Рабочее решение, которое я нашел, кажется уродливым:

begin
    while item=enum.next
        puts item
    end
rescue StopIteration
end

Итак, вопрос: есть ли более приятное рубиновое решение для этой вещи? И почему цикл for в Ruby действует таким образом?

Ответы [ 2 ]

0 голосов
/ 28 апреля 2018

Чтобы ответить на ваш вопрос напрямую, ваш текущий код находится в правильных строках, но слишком сложен. Вам нужно только сделать:

enum = (1..9).each
first = enum.next
second = enum.next

loop { puts enum.next }

Цикл будет break, как только enum достигнет своего конца; loop автоматически спасет StopIteration для вас. Он будет повторно поднят, только если вы снова вызовете enum.next после цикла, чего здесь не происходит.

Однако, как указал @mudasobwa, использование таких перечислений довольно обычно; более распространенным было бы использование (1..9).each_with_index и явная обработка первых выходов по их индексу.

0 голосов
/ 28 апреля 2018

В ruby ​​настоятельно рекомендуется не использовать for, while и until, если вы не знаете, что и почему вы делаете.

Я с трудом представляю себе реальную проблему, когда нужно что-то сделать специальное на первых двух элементах Enumerable (это, возможно, означает архитектурную проблему), но вместо этого:

enum.next
enum.next
loop do
  begin
    puts enum.next
  rescue StopIteration
    break 
  end
end

Обновление: rescue там не нужно, см. Разъяснение в ответе @ TomLord.

Вам лучше сделать это:

enum.with_index do |element, idx|
  print "First " if idx == 0
  print "Second " if idx == 1
  puts element
end
Внутренние элементы

Iterator почти никогда не должны вызываться явно, вместо этого используйте эффективную и идиоматическую итерацию, отображение и сокращение.

...