Python 标尺序列生成器

Python Ruler Sequence Generator

我想了很久如何在Python中定义一个标尺序列的生成函数,它遵循序列的第一个数字(从1开始)出现的规则一次,接下来的两个数字会出现两次,接下来的三个数字会出现三次,等等

所以我想要得到的是 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7 等。

我知道这样做的方法是有两个独立的计数生成器 (itertools.count(1)),然后对于一个生成器中的每个数字,从另一个生成器中生成数字:

def rul():
    num = itertools.count(1) 
    repeator = itertools.count(1)
    for x in range(next(repeator)):
        yield from num

但是如果我在这个函数上点击 next(),我只会返回常规的 1,2,3,4.. 序列...

如有任何帮助,我们将不胜感激。

itertools.repeat怎么样?

import itertools

def ruler():
    num = rep_count = 0
    while True:
       rep_count += 1
       for i in range(rep_count):
           num += 1
           yield from itertools.repeat(num, rep_count)

没有 itertools 的普通旧 python 怎么样?

def ruler():
    counter = 1
    n = 1
    while True:
        for i in range(counter):
            for j in range(counter):
                yield n
            n += 1
        counter += 1

以我的愚见,这是针对此类情况的最清晰、最直接的解决方案

您无需使用 itertools 中的 count()repeat() 编写自己的函数即可获得这样的生成器:

from itertools import repeat,count

i   = count(1,1)
rul = (n for r in count(1,1) for _ in range(r) for n in repeat(next(i),r))

for n in rul: print(n, end = " ")

# 1 2 2 3 3 4 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 10 10 10 10 11 11 ...

如果您想在 itertools 上全力以赴,您将需要 countrepeatchain

您可以按如下方式对序列中的数字进行分组,其中 每个组对应于 repeat:

的单个实例
1          # repeat(1, 1)
2 2        # repeat(2, 2)
3 3        # repeat(3, 2)
4 4 4      # repeat(4, 3)
5 5 5      # repeat(5, 3)
6 6 6      # repeat(6, 3)
7 7 7 7    # repeat(7, 4)
...

所以我们可以定义ruler_numbers = chain.from_iterable(map(repeat, col1, col2)),只要我们能适当定义col1col2即可。

col1 很简单:就是 count(1).

col2也不复杂多少;我们可以将它们与原始序列类似地分组:

1         # repeat(1, 1)
2 2       # repeat(2, 2)
3 3 3     # repeat(3, 3)
4 4 4 4   # repeat(4, 4)
...

我们也可以使用 chain.from_iterablemap 生成: chain.from_iterable(map(repeat, count(1), count(1))).

最后,我们在 Python 中编写 Lisp 的最佳尝试中得到了最终结果 :)

from itertools import chain, repeat, count
ruler_numbers = chain.from_iterable(
                  map(repeat, 
                      count(1),
                      chain.from_iterable(
                        map(repeat,
                            count(1),
                            count(1)))))

或者如果你想用辅助函数稍微清理一下:

def concatmap(f, *xs):
    return chain.from_iterable(map(f, *xs))

ruler_numbers = concatmap(repeat, 
                          count(1),
                          concatmap(repeat,
                                    count(1),
                                    count(1)))