使用Python创建一个数字逐渐增加的列表

8
我该如何编写一个函数来创建一个列表,使得列表中包含的数字数量每次增加到指定值?
例如,如果最大值为4,则该列表将包含:
```python [1, 2, 3, 4] ```
1, 2, 2, 3, 3, 3, 4, 4, 4, 4

很难解释我正在寻找的内容,但从示例中我认为你会理解!谢谢。

7
好的,你尝试过什么? - Rohit Jain
你需要跟踪调用此函数的次数。你可以使用全局变量或静态变量,在每次调用后将其传递给函数并递增。 - Florin Stingaciu
你想要 f(2) -> [1, 2, 2] 吗? - Useless
2
我其实不明白这个问题。 - alexvassel
5
没有尝试过任何例子,我感觉我们只是在替那个人完成功课。 - Izkata
@Izkata 如果你看一下 OP 在这个网站上的历史记录,你可能会有不同的想法。 - yurisich
8个回答

17

我将使用itertools.chain

itertools.chain(*([i] * i for i in range(1, 5)))

或使用itertools.chain.from_iterable来稍微地更懒惰一些:


itertools.chain.from_iterable([i] * i for i in range(1, 5))
并且,如果你极度懒惰,可以与itertools.repeat配对使用--(如果你正在使用Python 2.x,则使用xrange):
import itertools as it
it.chain.from_iterable(it.repeat(i, i) for i in range(1, 5))

作为一个函数:

def lazy_funny_iter(n):
    return it.chain.from_iterable(it.repeat(i, i) for i in range(1, n+1))

def lazy_funny_list(n):
    return list(lazy_funny_iter(n))

根据提问者的需求,您还可以使用itertools.count()替换范围,因为您正在进行所有操作的惰性计算。 - Neil G
@NeilG -- 感谢你的投票支持。count 在这里似乎会很棘手。我的印象是它可以无限计数——这将使它与其他东西链接起来非常困难。xrange 是 py2k 中的延迟函数,而 range 是 py3k 中的延迟函数,因此应该不会出现获取类似于延迟范围函数的问题。 - mgilson
是的,我只是在想,如果序列的使用者将其与有限序列一起压缩,则无限计数可以节省调用者传递参数的麻烦。 - Neil G

16

一个嵌套循环。 这是非常基本的实现方式。 有更好的方法,但这应该能给你一个大致的想法。

>>> def listmaker(num):
    l = []
    for i in xrange(1, num+1):
        for j in xrange(i):
            l.append(i)
    return l

>>> print listmaker(4)
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

这里使用列表推导式实现:

>>> def listmaker2(num):
    return [y for z in [[x]*(x) for x in xrange(1, num+1)] for y in z]

>>> print listmaker2(4)
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

按照建议使用 extend 方法。

>>> def listmaker3(num):
    l = []
    for i in xrange(1, num+1):
        l.extend([i]*(i))
    return l

>>> print listmaker3(4)
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

为什么不使用“extend”?如果最终数据不需要排序,使用它应该可以降低复杂度。 - luke14free
@luke14free -- 问题陈述中没有暗示最终数据不需要排序。当然,你可以使用for i in xrange(1,num+1)作为外层循环,执行l.extend([i]*i) - mgilson
同意!我猜楼主想要一个排序的解决方案。 - luke14free
1
@InbarRose -- 你可以将这句话添加到你的原始回答中,这样就避免了一个不必要的空循环。 - mgilson
@mgilson 是的,谢谢提醒,我在编辑中漏掉了。 - Inbar Rose
显示剩余4条评论

9
您可以使用递归函数:
def my_func(x):
    if x <= 0:
        return []
    else:
        return my_func(x-1) + [x] * x

>>> my_func(4)
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

7
In [1]: def funny_list(n):
   ...:     return sum(([i]*i for i in range(1, n+1)), [])
   ...: 

In [2]: funny_list(4)
Out[2]: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

然而,与 itertools.chain 不同,这不能变成一个真正的生成器,后者是首选方法。


2
有趣的sum用法 - user1012451
4
使用sum这种方式需要注意的一点是它会表现出二次行为,因此如果n是100,它将比itertools.chain慢数百倍。当然,通常情况下这并不重要。 - DSM
@DSM 嗯。是的。对每个数组求和 :) - user1012451

4
问题的不同视角(稍微简单一些):
>>> a = range(1,5)
>>> for i in range(2,5):
...     a.extend(range(i,5))
... 
>>> print sorted(a) #Remove the sort if you don't need it
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

4
创建如图所示的列表的一种相对直接的方法是通过:
[i for i in range(1,n+1) for j in range(i)]

其中 n 是出现在列表中的最大数。以上方法与几个先前提出的答案相同,但表达更为简洁。

到目前为止,所有提到的方法的替代方法是注意到列表的第 i 个元素近似等于 2*i 的平方根的整数部分。稍加调整,可以制作出一个相当简单的生成器,如下所示。

def gen_nnlist(nmax):
    n = 1
    while n < nmax*(nmax+1):
        yield int(n**.5+.5)
        n += 2

以下是在 Python 2.7.3 解释器中运行代码的一些示例输出:

>>> print [i for i in gen_nnlist(4)]
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
>>> print [i for i in gen_nnlist(6)]
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6]
>>> fun = gen_nnlist(3)
>>> for i in fun: print i
... 
1
2
2
3
3
3
>>>

出乎意料的是,我不知道列表推导式可以像这样嵌套在一个扁平的方式中。这有点酷,尽管我肯定会忘记哪个循环在内部,哪个循环在外部... - mgilson

3
>>> list(''.join([str(x) * x for x in range(1, 5)]))

2
我会选择使用发电机:
>>> def growingSeq(maxN):
...     for n in range(1,maxN+1):
...         for _ in range(n):
...             yield n
... 
>>> growingSeq(4)
<generator object growingSeq at 0x1004db280>
>>> list(growingSeq(4))
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

如果我们真的需要生成器,就要充分利用语法xrange而不是range - user1012451
在大多数实际使用情况下,键入和阅读range而不是xrange的便利性将比两者之间的运行时差异节省更多时间。此外,Python 3。 - Russell Borogove

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接