问题
I would like to use an enumerator like [1,2,3].cycle
and count how many times I've gone through the iterations. [1,2,3].cycle.count
creates an infinite loop and doesn't bring the iteration count. I'm playing a card game, and it cycles through the players. It's easy in the game to say:
@round = 0
if @turn == 1
@round += 1
end
and it works. But I would like to know how to change count
or add iter
only for enumerators with cycle
into something like this:
module Enumerable
def cycle
super
def count
puts "Hi"
end
end
end
Since everything in Ruby is an Object, I should be able to create functions within functions as this case works:
def x
def y
puts 1
end
end
x.y
# => 1
How can I overwrite the behaviour of count
only within a cycle
enumerator or at least create a working method iter
within the cycle
Enumerator?
回答1:
You can put something like that together fairly easily. Something like
class Iter < Array
attr_reader :iteration
def initialize(*args)
super(*args)
@pointer = 0
@iteration = 1 # Current iteration
end
def next
self[@pointer].tap {
@pointer = (@pointer + 1) % size
@iteration += 1 if @pointer == 0
}
end
end
iter = Iter.new [1,2,3]
7.times { puts 'iteration %d: %d' % [iter.iteration, iter.next] }
# iteration 1: 1
# iteration 1: 2
# iteration 1: 3
# iteration 2: 1
# iteration 2: 2
# iteration 2: 3
# iteration 3: 1
回答2:
Another option, which does not need to keep count of the number of calls to next:
class CycledArray
def initialize(arr)
@cycle = arr.cycle.each_with_index
@iteration_length = arr.length
end
def next
@cycle.next.first
end
def iterations
@cycle.peek.last/@iteration_length
end
end
arr = CycledArray.new([1,2,3])
56.times { arr.next }
arr.next
# => 3
arr.iterations
# => 19
回答3:
This should work:
ary = [1,2,3]
ary.cycle.with_index do |n,i|
iteration_number = i / ary.size
puts "n: #{n} iteration: #{iteration_number}"
break if i == 10
end
回答4:
So many ways to do this, eh? You could also subclass Array
, create an enumerator arr.cycle
and step through it using Enumerator#next:
class CycleArr < Array
def initialize arr
@sz = arr.size
@enum = arr.cycle
end
def next
@count = (@count ||= 0) + 1
@enum.next
end
def cycle_count
1 + (@count - 1) % @sz
end
end
c = CycleArr.new(['dog', 'cat', 'pig'])
7.times { p [c.next, c.cycle_count] }
# ["dog", 1]
# ["cat", 2]
# ["pig", 3]
# ["dog", 1]
# ["cat", 2]
# ["pig", 3]
# ["dog", 1]
回答5:
Some of the answers above contain hidden problems in the way iteration/cycle_count is returned; for example, the iteration/count_cycle may be wrong if the data is requested before the iteration is checked. A more useful method would return [object, iteration]
(analogous to the way #each_with_index
returns [object, index]
) and would take a block.
Drawing from @Ursus and @7stud based on the similar question I asked here, I like this solution:
module Enumerable
def each_with_iteration
Enumerator.new do |y|
iteration = 1
enum = self.cycle
loop do
enum.peek # raises StopIteration if self.empty?
self.size.times do
e = [enum.next, iteration]
y << (block_given? ? yield(e) : e)
end
iteration += 1
end
end
end
end
This makes it a close analog to Enumerable#each_with_index
, for example:
>> enum = %w(dog duck sheep rabbit).each_with_iteration
=> #<Enumerator: ...>
>> 7.times { p enum.next }
["dog", 1]
["duck", 1]
["sheep", 1]
["rabbit", 1]
["dog", 2]
["duck", 2]
["sheep", 2]
=> 7
>> enum.first(7)
=> [["dog", 1],
["duck", 1],
["sheep", 1],
["rabbit", 1],
["dog", 2],
["duck", 2],
["sheep", 2]]
And with a block:
>> animals = %w(dog duck sheep rabbit)
=> ["dog", "duck", "sheep", "rabbit"]
>> enum = animals.each_with_iteration { |animal, iter| "This is #{animal} number #{iter}" }
=> #<Enumerator: ...>
>> enum.first(7)
=> ["This is dog number 1",
"This is duck number 1",
"This is sheep number 1",
"This is rabbit number 1",
"This is dog number 2",
"This is duck number 2",
"This is sheep number 2"]
This also works as expected on a Hash, Set, Range, or other Enumerable.
EDIT:
Added a guard to keep from entering an infinite loop if self.empty?
Incorporated
yield
to operate on a block.
来源:https://stackoverflow.com/questions/24764323/count-iteration-on-the-enumerable-cycle