2010-12-17 58 views
5

我想知道如果下面的代码可以写得更好一些。基本上,我想为(x, y) meshgrid计算z = f(x, y)重写一个更好,也许更短的方式双循环

a = linspace(0, xr, 100)                 
b = linspace(0, yr, 100)                 

for i in xrange(100): 
    for j in xrange(100): 
     z[i][j] = f(a[i],b[j]) 

回答

15

是的。你在问题中提出的代码很好。

不要以为几行就是“好”或“酷”。重要的是清晰度,可读性和可维护性。其他人应该能够理解你的代码(你应该在12个月内了解它,当你需要找到一个bug时)。许多程序员,尤其是年轻人,都需要“聪明”的解决方案。他们不是。这对Python社区来说非常棒。我们受这种错误的困扰比其他人少得多。

+1

我upvoted这一点,因为它是我学习自己一个教训,但如果他们只是列出那么我认为我的解决方案比OP的代码更好,因为它回避外来迭代器。在相同的假设下,wheatie的答案更好。 – aaronasterling 2010-12-18 00:01:18

+1

迭代器仍然存在。它不会回避任何事情。这就是说,我一直使用列表推导,当然,但如果我必须将它们嵌套在一起,我将它们展开,以便它们更易于阅读。 – 2010-12-18 07:32:44

5

你可以做类似

z = [[f(item_a, item_b) for item_b in b] for item_a in a] 
2

如果你把它一下子,你可以用一个列表理解;

[[f(a[i], b[j]) for j in range(100)] for i in range(100)] 

如果您需要使用z是已经存在的,但是,你不能做到这一点,你的代码是你会得到最整洁。

增加:我不知道这个lingrid是干什么的,但是如果它产生一个100个元素的列表,使用aaronasterling的列表理解;没有必要创建额外的迭代器。

4

你可以使用itertools“产品:

[f(i,j) for i,j in product(a, b)] 

,如果你真的想那些5条线路缩入1,则:

[f(i,j) for i,j in product(linspace(0,xr,100), linspace(0,yr,100)] 

把它更进一步,如果你想要的功能xryr您也可以将0和100的范围预设为其他值:

def ranged_linspace(_start, _end, _function): 
    def output_z(xr, yr): 
     return [_function(i, j) for i,j in product(linspace(_start, xr, _end), linspace(_start, yr, _end))] 
    return output_z 
+0

应该指出的是,所有这些解决方案都会产生一个一维列表,而不是像OP的解决方案那样的嵌套列表。 – aaronasterling 2010-12-18 00:32:54

0

这显示了一般结果。 a被制成一个6长的列表,并且b是4长的。结果是6个列表的列表,每个嵌套列表长4个元素。

>>> def f(x,y): 
...  return x+y 
... 
>>> a, b = list(range(0, 12, 2)), list(range(0, 12, 3)) 
>>> print len(a), len(b) 
6 4 
>>> result = [[f(aa, bb) for bb in b] for aa in a] 
>>> print result 
[[0, 3, 6, 9], [2, 5, 8, 11], [4, 7, 10, 13], [6, 9, 12, 15], [8, 11, 14, 17], [10, 13, 16, 19]] 
0

我想这就是你要找

z = [[a+b for b in linspace(0,yr,100)] for a in linspace(0,xr,100)] 
0

linspace的一行代码,实际上看起来可能是np.linspace。如果是,你可以在numpy的数组操作,而无需显式地重复:

z = f(x[:, np.newaxis], y) 

例如:

>>> import numpy as np 
>>> x = np.linspace(0, 9, 10) 
>>> y = np.linspace(0, 90, 10) 
>>> x[:, np.newaxis] + y # or f(x[:, np.newaxis], y) 
array([[ 0., 10., 20., 30., 40., 50., 60., 70., 80., 90.], 
     [ 1., 11., 21., 31., 41., 51., 61., 71., 81., 91.], 
     [ 2., 12., 22., 32., 42., 52., 62., 72., 82., 92.], 
     [ 3., 13., 23., 33., 43., 53., 63., 73., 83., 93.], 
     [ 4., 14., 24., 34., 44., 54., 64., 74., 84., 94.], 
     [ 5., 15., 25., 35., 45., 55., 65., 75., 85., 95.], 
     [ 6., 16., 26., 36., 46., 56., 66., 76., 86., 96.], 
     [ 7., 17., 27., 37., 47., 57., 67., 77., 87., 97.], 
     [ 8., 18., 28., 38., 48., 58., 68., 78., 88., 98.], 
     [ 9., 19., 29., 39., 49., 59., 69., 79., 89., 99.]]) 

但你也可以使用np.ogrid,而不是两个linspace

进口numpy的作为np

>>> x, y = np.ogrid[0:10, 0:100:10] 
>>> x + y # or f(x, y) 
array([[ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90], 
     [ 1, 11, 21, 31, 41, 51, 61, 71, 81, 91], 
     [ 2, 12, 22, 32, 42, 52, 62, 72, 82, 92], 
     [ 3, 13, 23, 33, 43, 53, 63, 73, 83, 93], 
     [ 4, 14, 24, 34, 44, 54, 64, 74, 84, 94], 
     [ 5, 15, 25, 35, 45, 55, 65, 75, 85, 95], 
     [ 6, 16, 26, 36, 46, 56, 66, 76, 86, 96], 
     [ 7, 17, 27, 37, 47, 57, 67, 77, 87, 97], 
     [ 8, 18, 28, 38, 48, 58, 68, 78, 88, 98], 
     [ 9, 19, 29, 39, 49, 59, 69, 79, 89, 99]]) 

它有些依赖你在f是什么。如果它包含像math.sin功能则需要通过numpy.sin替换它们。

如果它不是关于numpy,那么你应该坚持要么你的选择或循环时,可以选择使用enumerate

for idx1, ai in enumerate(a): 
    for idx2, bj in enumerate(b): 
     z[idx1][idx2] = f(ai, bj) 

这样做,你不需要硬编码的range(或xrange)或优势使用len(a)作为输入。但总的来说,如果没有巨大的性能差异然后使用你和使用你的代码别人会很容易理解的方法。


如果abnumpy.array当时的会有一个显著的性能差异,因为numpy的可能,如果没有list <更快的处理阵列 - 要求>numpy.array转换。

相关问题