想象一个离散的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 ) )
Run Code Online (Sandbox Code Playgroud)
一个简单的
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)
Run Code Online (Sandbox Code Playgroud)
验证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)
Run Code Online (Sandbox Code Playgroud)
它收集所有点,然后过滤那些不符合条件的点.
我希望可能有一种方法可以纠正第一次尝试的实现,或者使这些表达式更具可读性或紧凑性.
首先,我建议您将三重嵌套for循环替换为itertools.product(),如下所示:
import itertools as it
it_1 = it.product(range(-dist, dist+1), repeat=3)
Run Code Online (Sandbox Code Playgroud)
如果您使用的是 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)
Run Code Online (Sandbox Code Playgroud)
这将避免 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)
Run Code Online (Sandbox Code Playgroud)
我刚刚更改了您原始代码的代码。x、y 和 z 的每个范围均调整为以原点为中心。当我用半径 0 测试此代码时,我正确地返回了一个点,即原点。
请注意,我为函数提供了参数,让您可以指定半径、原点,甚至用于 epsilon 的值,每个参数都有默认值。我还将原点元组解压缩为显式变量;我不确定 Python 是否会优化索引操作,但这样我们就知道循环内不会进行任何索引。(我认为 Python 编译器可能会将limit计算提升到循环之外,但实际上我更喜欢将其放在自己的行中,如此处所示,以提高可读性。)
我认为上面的内容与用原生 Python 编写的速度差不多,而且我认为这是可读性的一个很大的提高。
PS 如果使用 Cython 重做,这段代码可能会运行得更快。
编辑:代码按照 @eryksun 在评论中的建议进行了简化。
| 归档时间: |
|
| 查看次数: |
156 次 |
| 最近记录: |