Python 以更好或更短的方式重写双循环
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4475704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rewrite a double loop in a nicer and maybe shorter way
提问by nos
I am wondering if the following code can be written in a somewhat nicer way. Basically, I want to calculate z = f(x, y)for a (x, y)meshgrid.
我想知道是否可以用更好的方式编写以下代码。基本上,我想计算z = f(x, y)的(x, y)meshgrid。
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])
采纳答案by Lennart Regebro
Yeah. Your code as presented in the question is nice.
是的。您在问题中提供的代码很好。
Do not ever think that few lines is "nice" or "cool". What counts is clarity, readability and maintainability. Other people should be able to understand your code (and you should understand it in 12 months, when you need to find a bug).
永远不要认为几行是“好”或“酷”。重要的是清晰度、可读性和可维护性。其他人应该能够理解你的代码(你应该在 12 个月内理解它,当你需要找到一个错误时)。
Many programmers, especially young ones, think that "clever" solutions are desirable. They are not. And that's what is so nice with the python community. We are much less afflicted by that mistake than others.
许多程序员,尤其是年轻人,认为“聪明”的解决方案是可取的。他们不是。这就是 Python 社区的魅力所在。与其他人相比,我们受这个错误的影响要少得多。
回答by aaronasterling
you could do something like
你可以做类似的事情
z = [[f(item_a, item_b) for item_b in b] for item_a in a]
回答by Chris Morgan
If you set it all at once, you can use a list comprehension;
如果一次性全部设置,可以使用列表推导式;
[[f(a[i], b[j]) for j in range(100)] for i in range(100)]
If you need to use a zthat's already there, however, you can't do that and your code is about the neatest you'll get.
z但是,如果您需要使用已经存在的 ,则不能这样做,并且您的代码将是最简洁的。
Addition:I don't know with what this lingriddoes, but if it produces a 100-element list, use aaronasterling's list comprehension; no point in creating an extra iterator if you don't need to.
另外:我不知道这lingrid是做什么的,但是如果它生成一个 100 元素的列表,请使用 aaronasterling 的列表理解;如果不需要,创建额外的迭代器没有意义。
回答by wheaties
You could use itertools' product:
您可以使用itertools的产品:
[f(i,j) for i,j in product( a, b )]
and if you really want to shrink those 5 lines into 1 then:
如果您真的想将这 5 行缩小为 1,则:
[f(i,j) for i,j in product( linspace(0,xr,100), linspace(0,yr,100)]
To take it even further if you want a function of xrand yrwhere you can also preset the ranges of 0 and 100 to something else:
把它更进一步,如果你想要的功能xr,并yr在这里你还可以预设的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
回答by hughdbrown
This shows the general result. ais made into a list 6-long and bis 4-long. The result is a list of 6 lists, and each nested list is 4 elements long.
这显示了一般结果。a被制成6长和b4长的列表。结果是一个包含 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]]
回答by Muhammed Aslam
I think this is the one line code that you looking for
我认为这是您要查找的单行代码
z = [[a+b for b in linspace(0,yr,100)] for a in linspace(0,xr,100)]
回答by MSeifert
Your linspaceactually looks like it could be np.linspace. If it is you could operate on the numpy arrays without having to iterate explicitly:
你linspace实际上看起来可能是np.linspace。如果是这样,您可以对 numpy 数组进行操作而无需显式迭代:
z = f(x[:, np.newaxis], y)
For example:
例如:
>>> 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.]])
But you could also use np.ogridinstead of two linspace:
但是你也可以使用np.ogrid而不是两个linspace:
import numpy as np
将 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]])
It somewhat depends on what you're fis. If it contains functions like math.sinyou need to replace them by numpy.sin.
这在某种程度上取决于你是什么f。如果它包含类似math.sin您需要将它们替换为numpy.sin.
If it's not about numpythen you should stick either with your option or optionally using enumeratewhen looping:
如果不是,numpy那么您应该坚持使用您的选项或enumerate在循环时选择使用:
for idx1, ai in enumerate(a):
for idx2, bj in enumerate(b):
z[idx1][idx2] = f(ai, bj)
This has the advantage that you don't need to hardcode your range(or xrange) or use the len(a)as input. But in general if there is not a huge performance difference 1then use the method you and others using your code will understand easily.
这样做的优点是您不需要硬编码您的range(或xrange) 或将len(a)用作输入。但总的来说,如果没有巨大的性能差异1则使用您和使用您的代码的其他人将很容易理解的方法。
1If your aand bare numpy.arrays then there would be a significant performance difference because numpy can process the arrays much faster if no list<->numpy.arrayconversions are required.
1如果您的a和b是numpy.arrays 那么会有显着的性能差异,因为如果不需要list<->numpy.array转换,numpy 可以更快地处理数组。

