【问题标题】:Creating list of individual list items multiplied n times创建单个列表项的列表乘以 n 次
【发布时间】:2013-05-28 16:19:37
【问题描述】:

我对 Python 还很陌生,认为这应该是一个相当普遍的问题,但找不到解决方案。我已经查看了this page 并发现它对一个项目很有帮助,但我正在努力将示例扩展到多个项目而不使用“for”循环。我正在通过 Emcee 为 250 名步行者运行这段代码,所以我正在寻找可能的最快方式。

我有一个数字列表a = [x,y,z],我想重复b = [1,2,3] 次(例如),所以我最终得到了一个列表列表:

[
 [x],
 [y,y],
 [z,z,z]
]

我的“for”循环是:

c = [ ]
for i in range (0,len(a)):
    c.append([a[i]]*b[i])

这正是我想要的,但这意味着我的代码非常慢。我还尝试天真地将 a 和 b 转换为数组并执行[a]*b,希望它可以逐个元素地相乘,但没有乐趣。

【问题讨论】:

    标签: python arrays list loops emcee


    【解决方案1】:

    您可以在此处使用zip 和列表推导:

    >>> a = ['x','y','z']
    >>> b = [1,2,3]
    >>> [[x]*y for x,y in zip(a,b)]
    [['x'], ['y', 'y'], ['z', 'z', 'z']]
    

    或:

    >>> [[x for _ in xrange(y)] for x,y in zip(a,b)]
    [['x'], ['y', 'y'], ['z', 'z', 'z']]
    

    zip 将首先在内存中创建整个列表,以获取迭代器使用itertools.izip

    如果a 包含可变对象,如列表或列表列表,那么您可能必须在此处使用copy.deepcopy,因为修改一个副本也会更改其他副本。:

    >>> from copy import deepcopy as dc
    >>> a = [[1 ,4],[2, 5],[3, 6, 9]]
    >>> f = [[dc(x) for _ in xrange(y)] for x,y in zip(a,b)]
    
    #now all objects are unique
    >>> [[id(z) for z in x] for x in f]
    [[172880236], [172880268, 172880364], [172880332, 172880492, 172880428]]
    

    timeit 比较(忽略导入):

    >>> a = ['x','y','z']*10**4
    >>> b = [100,200,300]*10**4
    
    >>> %timeit [[x]*y for x,y in zip(a,b)]
    1 loops, best of 3: 104 ms per loop
    
    >>> %timeit [[x]*y for x,y in izip(a,b)]
    1 loops, best of 3: 98.8 ms per loop
    
    >>> %timeit map(lambda v: [v[0]]*v[1], zip(a,b))
    1 loops, best of 3: 114 ms per loop
    
    >>> %timeit map(list, map(repeat, a, b))
    1 loops, best of 3: 192 ms per loop
    
    >>> %timeit map(list, imap(repeat, a, b))
    1 loops, best of 3: 211 ms per loop
    
    >>> %timeit map(mul, [[x] for x in a], b)
    1 loops, best of 3: 107 ms per loop
    
    >>> %timeit [[x for _ in xrange(y)] for x,y in zip(a,b)]
    1 loops, best of 3: 645 ms per loop
    
    >>> %timeit [[x for _ in xrange(y)] for x,y in izip(a,b)]
    1 loops, best of 3: 680 ms per loop
    

    【讨论】:

    • 我建议提及itertools.izip
    • 谢谢!不过,“for”循环是否仍会减慢代码速度?
    • @user2444731 “慢”是什么意思?为什么你认为for-loop 很慢?与什么相比慢?
    • 由于用户是新用户,指出 [x]*y 创建对 x 的 y 引用可能是明智的,这在某些情况下可能会出现问题。就像一个被改变了一样,它们都可能被改变。
    • 您可能应该在提出问题时提到这是针对蒙特卡洛算法的。上下文很有帮助。
    【解决方案2】:

    最快的方法是使用map()operator.mul()

    >>> from operator import mul
    >>> map(mul, [['x'], ['y'], ['z']], [1, 2, 3])
    [['x'], ['y', 'y'], ['z', 'z', 'z']]
    

    【讨论】:

    • +1 我刚刚在您发布它时发现了这一点(但是输入不是列表列表)
    【解决方案3】:
    >>> from itertools import repeat
    >>> from itertools import starmap
    >>> a = ['x','y','z']
    >>> b = [1,2,3]
    >>> starmap(repeat,zip(a,b))
    

    starmap 返回一个 iterable,其中包含的值等于调用 repeat 的结果,参数等于元组中包含的值,在本例中为 ('x',1)

    >>> for p in starmap(repeat,zip(a,b)):
        print(list(p))
    
    
    ['x']
    ['y', 'y']
    ['z', 'z', 'z']
    

    【讨论】:

    • 请注意,您必须在starmap 上致电map(list, ...) 以获取列表列表
    【解决方案4】:

    @kirelagin 建议了一个没有for 循环的版本,这是一个也没有lambdas 的版本(请记住@AshwiniChaudhary 的解决方案是最易读的)

    >>> from itertools import repeat
    >>> a = ['x','y','z']
    >>> b = [1,2,3]
    >>> map(list, map(repeat, a, b))
    [['x'], ['y', 'y'], ['z', 'z', 'z']]
    

    >>> map(repeat, a, b)
    [repeat('x', 1), repeat('y', 2), repeat('z', 3)]
    

    创建一个不占用内存中任何额外空间的repeat 对象列表(如果您想要一个惰性迭代器而不是列表,请在 Python 2.x 上使用imap),如果您只是想要迭代项目而不是存储它们)

    【讨论】:

      【解决方案5】:

      如果您出于某种原因不喜欢 for 循环,这是一个没有循环的版本:

      map(lambda v: [v[0]]*v[1], zip(a,b))
      

      我还应该警告你,这个版本比列表理解稍慢:

      $ a = ['hi']*100
      $ b = [20]*100
      
      $ %timeit map(lambda v: [v[0]]*v[1], zip(a,b))
      10000 loops, best of 3: 101 us per loop
      
      %timeit [[x]*y for x,y in zip(a,b)]
      10000 loops, best of 3: 74.1 us per loop
      

      如果您使用的是 Python 2,我还建议使用 itertools.izip 而不是 zip

      【讨论】:

        猜你喜欢
        • 2011-03-28
        • 2021-04-15
        • 1970-01-01
        • 2020-03-02
        • 1970-01-01
        • 1970-01-01
        • 2018-07-15
        • 1970-01-01
        相关资源
        最近更新 更多