具有多个 'for' 子句和单个 'if' 的 python 理解

标签 python python-3.x

想象一个离散的 x,y,z 空间:我正在尝试创建一个迭代器,它将返回位于距某个点一定径向距离的球体内的所有点。

我的方法是首先查看一个更大的立方体中的所有点,保证包含所有需要的点,然后剔除或跳过距离太远的点。

我的第一次尝试是:

x,y,z=(0,0,1)
dist=2
#this doesn't work
it_0=((x+xp,y+yp,z+zp) for xp in range(-dist,dist+1) for yp in range(-dist,dist+1) for zp in range(-dist,dist+1) if ( ((x-xp)**2+(y-yp)**2+(z-zp)**2) <= dist**2+sys.float_info.epsilon ) )

一个简单的

for d,e,f in it_0:
    #print(d,e,f)
    print( ((x-d)**2+(y-e)**2+(z-f)**2) <= dist**2+sys.float_info.epsilon,  d,e,f)

验证 it_0 没有产生正确的结果。我相信它仅将条件应用于第三个(即:z)“for”子句

以下作品:

it_1=((x+xp,y+yp,z+zp) for xp in range(-dist,dist+1) for yp in range(-dist,dist+1) for zp in range(-dist,dist+1))
it_2=filter( lambda p: ((x-p[0])**2+(y-p[1])**2+(z-p[2])**2) <= dist**2+sys.float_info.epsilon, it_1)

它收集所有的点,然后过滤那些不符合条件的点。

我希望有一种方法可以纠正第一次尝试的实现,或者使这些表达式更具可读性或更紧凑。

最佳答案

首先,我建议您将三重嵌套的 for 循环替换为 itertools.product(),如下所示:

import itertools as it
it_1 = it.product(range(-dist, dist+1), repeat=3)

如果您使用的是 Python 2.x,则应在此处使用 xrange() 而不是 range()

接下来,您可以不使用 filter() 而只使用生成器表达式:

it_2=(x, y, z for x, y, z in it_1 if ((x-p[0])**2+(y-p[1])**2+(z-p[2])**2) <= dist**2+sys.float_info.epsilon)

这会避免 Python 2.x 中的一些开销(因为 filter() 构建了一个列表),但是对于 Python 3.x 来说是差不多的;甚至在 Python 2.x 中,您也可以使用 itertools.ifilter()

但为了可读性,我会将整个东西打包成一个生成器,如下所示:

import itertools as it
import sys

def sphere_points(radius=0, origin=(0,0,0), epsilon=sys.float_info.epsilon):
    x0, y0, z0 = origin
    limit = radius**2 + epsilon
    for x, y, z in it.product(range(-radius, radius+1), repeat=3):
        if (x**2 + y**2 + z**2) <= limit:
            yield (x+x0, y+y0, z+z0)

我刚刚更改了您的原始代码。 x、y 和 z 的每个范围都被调整为以原点为中心。当我在半径为 0 的情况下测试此代码时,我正确地返回了一个点,即原点。

请注意,我为函数提供了参数,让您可以指定半径、原点,甚至是用于 epsilon 的值,每个参数都有默认值。我还将原点元组解包为显式变量;我不确定 Python 是否会优化索引操作,但这样我们就知道循环内不会进行任何索引操作。 (我认为 Python 编译器可能会将 limit 计算提升到循环之外,但实际上我更喜欢它单独一行,如此处所示,以提高可读性。)

我认为上面的代码与您用原生 Python 编写它的速度差不多,而且我认为它在可读性方面有了很大的改进。

附言如果使用 Cython 重做,这段代码可能会运行得更快。

http://cython.org/

编辑:按照@eryksun 在评论中的建议简化了代码。

关于具有多个 'for' 子句和单个 'if' 的 python 理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15603410/

相关文章:

python - 为什么 Python 的控制台在 Eclipse 中的调试视角中与 PyDev 分开?

python - 常见的 lisp 格式指令来打印列表

python - 使用 BeautifulSoup 调整 DOM 树中的所有文本

python - 重命名 pandas 数据框的第一行

python-3.x - 将 '000111010010111' 拆分为 ['000' ,'111' ,'0' , 1',' 0 0',' 1',' 0x9'104] 15

python - numpy ndarray 到 Pandas 数据框

python - 在虚拟机(Google Cloud Platform)中使用 Cron 定期运行 Python 脚本

Python:如何在给定数字数组的情况下绘制 cdf 函数

python-3.x - 在 python 中保留所有字母和数字字符

python - 我在输出中得到的模式末尾有额外的星号,这是不需要的