1

我觉得这应该很简单,但我坚持寻找一个简洁的解决方案。我提供的代码有效,并给出了我期望的输出,但我不觉得它是 Pythonic,它让我很紧张。

我使用基础数据集中的“griddata”生成了三组坐标 X、Y 和 Z。坐标在未知的总面积/形状(不一定是正方形/矩形)上均匀分布,产生 NaN 结果,我想忽略每个列表的边界。列表应该从“左下角”(在坐标系中)穿过 x 轴,在 y 方向上向上一个空间,然后从右到左,然后再继续。可能有奇数或偶数行。

无论方向如何,对每个点执行的操作都是相同的,并保证存在于 X 中的每个点都存在于 Y 和 Z 中,如下面的代码所示。

数组(列表?)的格式为 DataPoint[rows][columns]。

k = 0
for i in range(len(x)):
    if k % 2 == 0:  # cut left to right, then right to left
        for j in range(len(x[i])):
            if not numpy.isnan(x[i][j]):
                file.write(f'X{x[i][j]} Y{y[i][j]} Z{z[i][j]}')
    else:
        for j in reversed(range(len(x[i]))):
            if not numpy.isnan(x[i][j]):
                file.write(f'X{x[i][j]} Y{y[i][j]} Z{z[i][j]}')
    k += 1

我能想到的一种解决方案是在运行循环之前反转每个列表中的每隔一行。它会为我节省几行代码,但从性能的角度来看可能没有意义 - 有人有更好的建议吗?

通过列表的预期路线:

End════<══════╗
╔══════&gt;══════╝
╚══════&lt;══════╗
Start══>══════╝
4

3 回答 3

1

这是一个变体:

for i, (x_row, y_row, z_row) in enumerate(zip(x, y, z)):
    if i % 2:
        z_row = reversed(x_row)
        y_row = reversed(y_row)
        z_row = reversed(z_row)
    row_strs = list()
    for x_elem, y_elem, z_elem in zip(x_row, y_row, z_row):
        if not numpy.isnan(x_elem):
            row_strs.append(f"X{x_elem} Y{y_elem} Z{z_elem}")
    file.write("".join(row_strs))

注意事项

没有任何一种优化方法总是比其他任何方法都表现得更好。它还取决于代码处理的数据。这是我能想到的事情的列表,但不知道数据的样子:

  • for index range(len(sequence)):不是Python ic 的迭代方式。在这里,使用了foreach成语。如果需要索引,可以使用[ Python 3.Docs]: Built-in Functions - enumerate ( iterable, start=0 )
  • 由于上一个项目符号,这不再适用,但reversed(range(n))range(n - 1, -1, -1). 不知道后者是否更快,但看起来会
  • 使用 [Python 3.Docs] 一次迭代多个iterable :内置函数 - zip ( *iterables )
  • 不需要k,已经有i
  • 通常,在处理文件时,读取/写入更少倍大的数据块比读取/写入小很多倍的数据块更好(文件通常驻留在磁盘上并且磁盘操作很慢)。但是,默认情况下会发生缓冲(在Python操作系统级别),因此这不再是问题,但仍然存在。但与往常一样,这是资源(时间、内存……)之间的权衡。
    我选择每行写入一次文件(而不是每个元素一次 - 就像最初一样)。当然,第三种可能一次性写完所有东西,但我想对于更大的数据集,这不是最好的解决方案
  • 可能,一些优化也可能发生在NumPy级别(因为它处理批量数据的速度比Python代码(迭代)快得多),但我不是该领域的专家,也不知道数据的样子
于 2019-08-31T10:46:59.960 回答
0

我同意@Prune,您的代码看起来可读并且可以做它应该做的事情。您可以通过预先计算索引来稍微压缩它,就像这样(注意这从左上角开始):

import numpy as np

# generate some sample data
x = np.arange(100).reshape(10,10)

#precompute both directions
fancyranges = (
    list(range(len(x[0,:]))),
    reversed(list(range(len(x[0,:]))))
)

for a in range(x.shape[0]):
    # call appropriate directions
    for b in fancyranges[a%2]:
        # do things
        print(x[a,b])
于 2019-08-30T22:43:08.800 回答
0

您可以将可重复的代码移动到sub_func一个地方以进行进一步的更改

def func():

    def sub_func():
        # repeatable code
        if not numpy.isnan(x[i][j]):
            print(f'X{x[i][j]}...')

    k = 0
    for i in range(len(x)):
        if k % 2 == 0:  # cut left to right, then right to left
            for j in range(len(x[i])):
                sub_func()
        else:
            for j in reversed(range(len(x[i]))):
                sub_func()
        k += 1


func()
于 2019-08-30T23:31:13.837 回答