4

我想编写一个由数字数组表示的计数器,从:

[0, 0, 0]

这里的限制是,每个位置都有不同的上限,所以它不一定是 9 或其他东西,但它是给定的。例如:

[4, 2, 1]

这将导致以下递增序列:

[0, 0, 0]
[0, 0, 1] 
[0, 1, 0]
[0, 1, 1]
[0, 2, 0]
[0, 2, 1]
[1, 0, 0]
.
.
.

当然,我可以想到一个使用模数并将每个结转添加到下一个位置的解决方案。但是有人知道如何有效地实现这一点,分别使用漂亮的 Ruby 语法而不会使它过于混乱吗?

那是我天真的实现:

max = [10, 1, 1, 1, 10]
counter = [0, 0, 0, 0, 0]

i = counter.length-1
while counter != max do
   counter[i] = counter[i] + 1
   while counter[i] > max[i]
      counter[i] = 0
      i = i - 1
      counter[i] = counter[i] + 1
   end
   i = counter.length-1
 end
4

3 回答 3

3

我不确定效率,但这是我的看法:

start = [0, 0, 0]
cap = [4, 2, 1]

start.zip(cap).map{ |i, c| (i..c).to_a }.reduce(&:product).map &:flatten

产生类似的东西:

[[0, 0, 0],
 [0, 0, 1],
 [0, 1, 0],
 [0, 1, 1],
 [0, 2, 0],
 [0, 2, 1],
 [1, 0, 0],
 [1, 0, 1],
 [1, 1, 0],
 [1, 1, 1],
 [1, 2, 0],
 [1, 2, 1],
 [2, 0, 0],
 [2, 0, 1]...]
于 2013-02-03T05:33:32.280 回答
2

编辑:在您进行编辑之前,我正在写这篇文章。看起来你想要一个计数器对象,而不仅仅是输出一个列表。

1)我建议不要指定每个数字的限制而是(limit+1)。例如,对于 [second, minute, hour, day, year] 计数器,(对我来说)写 [60, 60, 24, 365] 而不是 [59,59,23,364] 更有意义。

2)如果您的计数器溢出数组的最后一个限制,您必须弄清楚该怎么做。我添加了一个计数到无穷大的额外位置。

3)我还建议颠倒数组的顺序,至少在内部表示中以避免反转下标。如果你不想那样,你可以.reverse在里面basesinitialize@digitsto_s

class MyCounter 
  def initialize bases
    @bases = bases
    @bases << 1.0/0 # Infinity
    @digits = Array.new(bases.size, 0)
    prod = 1
    @digit_values = [1] + @bases[0..-2].map { |b| prod *= b }
  end

  attr_reader :digit_values

  def to_s
    @digits
  end

  def increment(digit=0)
    v = @digits[digit] + 1
    if v < @bases[digit]
      @digits[digit] = v
    else 
      @digits[digit] = 0
      increment(digit+1)
    end
    self
  end

  def +(integer)
    (@digits.size - 1).step(0,-1).each do |i|
      @digits[i] += integer / @digit_values[i]
      integer = integer % @digit_values[i]
    end
    self
  end
end

c1 = MyCounter.new [2,3,5]
20.times { c1.increment; p c1 }

c2 = MyCounter.new [2,3,5]
c2 += 20
p c2
于 2013-02-03T06:36:44.203 回答
0

为每个上限创建一个数组,其值从 0 到上限。取第一个数组并计算其余数组的笛卡尔积。

caps = [4, 2, 1]
arrs = caps.map{|cap| (0..cap).to_a} #=>[[0, 1, 2, 3, 4], [0, 1, 2], [0, 1]]
p arrs.shift.product(*arrs)
# =>[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [0, 2, 0], [0, 2, 1], ...

如果您不想要一个包含结果的内存消耗数组,请提供一个块。product将一个一个地产生每个元素。

arrs = caps.map{|cap| (0..cap).to_a}
arrs.shift.product(*arrs){|el| puts el.join} #no resulting array
#000
#001
#010
#011
#...
于 2013-02-03T23:03:43.657 回答