Pythonic写循环的方法

Dim*_*oim 1 python loops list

我有两个列表:a = [1, 2, 3]b = [4, 5, 6].

我在python中使用了两个循环来减去每个元素的b每个元素a.

import numpy as np
a = [1, 2, 3]
b = [4, 5, 6]
p = -1
result = np.zeros(len(a)*len(a))
for i in range(0,len(a)):
    for j in range(0,len(a)):
        p = p + 1
        result[p] = a[i] - b[j]
Run Code Online (Sandbox Code Playgroud)

我的结果是对的:result = [-3., -4., -5., -2., -3., -4., -1., -2., -3.].

但是,我想知道是否有更优雅('pythonic')的方式来做到这一点.

Mat*_*ias 8

无需使用索引.您可以迭代值.

a = [1, 2, 3]
b = [4, 5, 6]
result = []
for x in a:
    for y in b:
        result.append(x - y)
Run Code Online (Sandbox Code Playgroud)

pythonic方式将是列表理解.

a = [1, 2, 3]
b = [4, 5, 6]
result = [x - y for x in a for y in b]
Run Code Online (Sandbox Code Playgroud)

请记住,你应该使用有意义的名称a,b,xy在真正的代码.


Ash*_*ary 5

Pythonic 方式将使用itertools.product,因为它返回传递给它的可迭代对象的笛卡尔积。由于不涉及 Python 循环,因此与使用循环的版本相比,它会更快:

>>> from operator import sub
>>> from itertools import starmap, product
>>> list(starmap(sub, product(a, b)))
[-3, -4, -5, -2, -3, -4, -1, -2, -3]
Run Code Online (Sandbox Code Playgroud)

在 NumPy 中,您可以使用此处提到的食谱来执行此操作:

>>> arr = np.dstack(np.meshgrid(a, b)).reshape(-1, 2)
>>> np.subtract(arr[:,0], arr[:,1])
array([-3, -2, -1, -4, -3, -2, -5, -4, -3])
Run Code Online (Sandbox Code Playgroud)

时序比较:

>>> b = [4, 5, 6]*1000
>>> a = [1, 2, 3]*1000
>>> %timeit list(starmap(sub, product(a, b)))
1 loops, best of 3: 464 ms per loop
>>> %timeit [x - y for x in a for y in b]
1 loops, best of 3: 491 ms per loop
>>> %%timeit                                 
result = []
for x in a:
    for y in b:
        result.append(x - y) #attribute lookup is slow
... 
1 loops, best of 3: 908 ms per loop
>>> %%timeit
result = [];append = result.append 
for x in a:
    for y in b:
        append(x - y)
... 
1 loops, best of 3: 617 ms per loop
#Numpy version will be little faster if a and b were nd arrays.
>>> %timeit arr = np.dstack(np.meshgrid(a, b)).reshape(-1, 2);np.subtract(arr[:,0], arr[:,1])
1 loops, best of 3: 573 ms per loop
Run Code Online (Sandbox Code Playgroud)


Dim*_*nek 5

既然你numpy已经在用了,就这么简单:

In [29]: numpy.repeat(a, len(b)) - numpy.tile(b, len(a))
Out[29]: array([-3, -4, -5, -2, -3, -4, -1, -2, -3])
Run Code Online (Sandbox Code Playgroud)

根据评论中的请求,OP 需要 1d 输出大小 N^2(尽管 2d 可能更自然),因为 numpy 提供了方便的函数将 N 大小的数组扩展到 N^M,即repeattile

numpy.repeat([1,0], 2)
array([1, 1, 0, 0])

numpy.tile([1,0], 2)
array([1, 0, 1, 0])
Run Code Online (Sandbox Code Playgroud)

一旦将ab都重新格式化为 的形状p,那就是numpy.