我想使用像[1,2,3].cycle
这样的枚举器,并计算我完成迭代的次数。 [1,2,3].cycle.count
创建一个无限循环,并且不会带来迭代计数。我正在玩纸牌游戏,它会循环播放玩家。游戏中很容易说:
@round = 0
if @turn == 1
@round += 1
end
它有效。但我想知道如何更改count
或仅为iter
的{{1}}枚举器添加cycle
:
module Enumerable
def cycle
super
def count
puts "Hi"
end
end
end
由于Ruby中的所有东西都是一个Object,我应该能够在函数中创建函数,因为这种情况有效:
def x
def y
puts 1
end
end
x.y
# => 1
如何仅在count
枚举器中覆盖cycle
的行为,或者至少在iter
枚举器中创建工作方法cycle
?
答案 0 :(得分:3)
你可以很容易地把这样的东西放在一起。像
这样的东西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
答案 1 :(得分:3)
另一种选择,不需要计算下一次呼叫次数:
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
答案 2 :(得分:2)
这应该有效:
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
答案 3 :(得分:1)
这么多方法,呃?您也可以创建一个枚举器Array
,创建一个枚举器arr.cycle
并使用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]
答案 4 :(得分:1)
上面的一些答案包含了返回iteration / cycle_count的方式中的隐藏问题;例如,如果在检查迭代之前请求数据,则iteration / count_cycle可能是错误的。一个更有用的方法是返回[object, iteration]
(类似于#each_with_index
返回[object, index]
的方式)并且会占用一个块。
根据我问here的类似问题,从@Ursus和@ 7stud绘图,我喜欢这个解决方案:
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
这使它与Enumerable#each_with_index
非常相似,例如:
>> 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]]
用一个块:
>> 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"]
这也可以在Hash,Set,Range或其他Enumerable上按预期工作。
编辑:
如果是self.empty,添加一个警卫以防止进入无限循环?
合并yield
以便对某个区块进行操作。