我可以操纵当前迭代的集合的当前迭代吗?

时间:2017-03-14 07:29:25

标签: arrays ruby iterator enumerator

假设我有一个@lines的集合,我想迭代它,但我想根据集合的内容来操纵迭代的方式,我该怎么做?

即。像这样的东西:

@lines.each_with_index do |line, index|
   if (index % 3 = 0)
      jump_to index == next_multiple_of_3
   end
end

所以看起来像这样:

Element | Index
a       | 1
b       | 2
c       | 3
f       | 6
g       | 7
h       | 8
i       | 9
l       | 12

我该怎么做?

修改1

请注意,正如我在下面的评论中所解释的那样,我并不总是希望跳到特定的倍数。基本上,我想跳转到一些任意索引,该索引由当前迭代中发生的事情决定。

首先,它可以向上跳转3个索引,但是下次它会向上跳转7个索引,然后在接下来的5个时间内跳转1个正常,然后它会跳过2个索引。

唯一不变的是确定它在原始迭代中如何进展的方式是基于当前迭代块内发生的事情。

5 个答案:

答案 0 :(得分:6)

使用while循环并自行管理索引。我们不鼓励人们这么做多年。但这是一个合适的案例。 :)

idx = 0
while idx < @lines.length
  line = @lines[idx]
  idx += condition ? x : y # or whatever logic you have
end

当然,这假设@lines能够随机访问。如果不是,请将其设为数组。

答案 1 :(得分:3)

如果要多次使用此逻辑,可能需要定义一个Enumerable方法:

module Enumerable
  def skip
    Enumerator.new do |yielder|
      skip_count = 0
      each_with_index do |object, index|
        if skip_count > 0
          skip_count -= 1
        else
          yielder << object
          skip_count = yield(object, index) || 0
        end
      end
    end
  end
end

您可以在任何Enumerable上使用它,您可以指定应跳过的元素数量,具体取决于当前元素和索引。

对于您的示例,您希望每6个元素跳过2个元素(例如4和5)。但是,你想要跳过index = 2之后的元素(Ruby索引从0开始):

puts ('a'..'z').skip{ |_, index| 2 if (index - 2) % 6 == 0 }.take(8)
# a
# b
# c
# f
# g
# h
# i
# l

答案 2 :(得分:1)

有人可以使用临时累加器:

@lines = (1..12).map(&:to_s)
JUMP_BY = 3
@lines.each.with_index.reduce(0) do |acc, (line, index)|
  next acc unless index == acc

  puts "line: #{line}"
  q, mod = index.divmod(JUMP_BY)
  (mod == JUMP_BY - 1) && (q % 2).zero? ? \
    (q + 2) * JUMP_BY - 1 : index + 1 # next 
end
#⇒ line: 1
#  line: 2
#  line: 3
#  line: 6
#  line: 7
#  line: 8
#  line: 9
#  line: 12

通过使JUMP_BY成为一种方法,人们可以根据需要做出复杂的决定。

答案 3 :(得分:1)

你使它变得比必要的更复杂。你不需要跳过迭代。只要在条件满足(un)时忽略该任务,就转到下一次迭代。

@lines.each_with_index do |line, index|
  next if index % 3 == 0
  ... # do the contentful things
end

答案 4 :(得分:1)

通过在枚举器上使用next,您可以跳过x步

def walk
    e = ('a'..'z').each
    while e.any?
        rand(5).times{e.next}
        puts e.peek
    end
rescue StopIteration => e
end