【问题标题】:making this nested for loop more pythonic使这个嵌套的 for 循环更加 Pythonic
【发布时间】:2021-09-25 19:21:11
【问题描述】:

我有一段笨拙(但有效)的代码,如图所示:

plus_cords = []
for i in range(len(pluses)):
    plus_cords.append([ [pluses[i][0], pluses[i][1]] ])
    for j in range(1, pluses[i][2] + 1):
        plus_cords[i].append([pluses[i][0] - j, pluses[i][1]])
        plus_cords[i].append([pluses[i][0] + j, pluses[i][1]])
        plus_cords[i].append([pluses[i][0], pluses[i][1] - j])
        plus_cords[i].append([pluses[i][0], pluses[i][1] + j])

其中 'pluses' 是由 3 个整数组成的列表。

pluses = [[0, 0, 0], [0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [1, 0, 0], [1, 4, 0], [2, 0, 0], [2, 1, 0], [2, 2, 0], [2, 3, 0], [2, 4, 0], [2, 4, 1], [2, 5, 0], [3, 0, 0], [3, 1, 0], [3, 4, 0], [4, 0, 0], [4, 1, 0], [4, 2, 0], [4, 3, 0], [4, 4, 0], [4, 5, 0]]

我正在寻找有关如何使其更具可读性和效率,基本上更“pythonic”的想法。

提前谢谢你

【问题讨论】:

标签: python python-3.x list for-loop


【解决方案1】:

与 Samwise 的答案类似,但分解为单独的步骤,实际上产生的结果与您的原始代码相同:

首先,当然,我们可以直接迭代pluses 的元素,而不是使用索引,然后将它们解包为它们的三个构成值,这已经使代码更具可读性:

plus_cords = []
for p0, p1, p2 in pluses:
    cords = [ [p0, p1] ]
    for j in range(1, p2 + 1):
        cords.append([p0 - j, p1])
        cords.append([p0 + j, p1])
        cords.append([p0, p1 - j])
        cords.append([p0, p1 + j])
    plus_cords.append(cords)

然后,我们可以尝试将内部循环转换为列表推导式。这有点棘手,因为我们必须使用嵌套生成器并将其解压缩到列表推导中以区分单个第一个元素和其余元素:

plus_cords = []
for p0, p1, p2 in pluses:
    cords = [[p0, p1], *(x for j in range(1, p2 + 1)
                           for x in ([p0 - j, p1], [p0 + j, p1], [p0, p1 - j], [p0, p1 + j]))]
    plus_cords.append(cords)

一旦我们有了它,我们也可以使外循环成为列表推导式。

plus_cords = [[[p0, p1], *(x for j in range(1, p2 + 1)
                             for x in ([p0 - j, p1], [p0 + j, p1], [p0, p1 - j], [p0, p1 + j]))]
              for p0, p1, p2 in pluses]

或者,您可以选择settuples(以防止重复)而不是第二步,并以j=0 开头获取[p0, p1] 案例。

plus_cords = [{x for j in range(p2 + 1)
                 for x in ((p0 - j, p1), (p0 + j, p1), (p0, p1 - j), (p0, p1 + j))}
              for p0, p1, p2 in pluses]

【讨论】:

  • 谢谢托拜厄斯。对于第一步中的外部 for 循环,“for p0, p1, p2 in pluses”和“for [p0, p1, p2] in pluses”有什么区别。无论哪种方式,我都能得到正确的结果。对于第 2 步,我肯定需要阅读才能理解。你有这个特定内容的资源吗?
  • @Muffi (1) 没有真正的区别。 (2) 最好在交互式 python shell 中尝试:简单列表文字[1, 2, 3];将另一个可迭代解包到列表文字 [1, *(2, 3)] 中;列出比较。 [x*2 for x in range(3)];列出 2 个循环的组合:[x+y for x in range(3) for y in range(3)],然后尝试以不同的方式组合它们。您在第 2 步中看到的是一个带有 2 个 for 循环的生成器表达式,它被解压缩到一个列表文字中。
【解决方案2】:

一般来说,最好是迭代列表的元素而不是按索引迭代它,并且通过理解而不是迭代地构建一个新列表appending。

plus_cords = [[
    [p0, p1], [p0 - j, p1], [p0 + j, p1], [p0, p1 - j], [p0, p1 + j]
] for [p0, p1, p2] in pluses for j in range(1, p2 + 1)]

不是肯定的,因为我没有可供pluses 测试的样本数据,但这应该在一般情况下。

【讨论】:

  • 这有语法错误。看起来for j 部分放错了位置
  • 是的,我确实尝试过这个,但我遇到了语法错误。虽然这看起来更具可读性,但谢谢。我将尝试调试语法错误并在此处发布。
  • 啊,是的,我们正在为pluses 的每个元素创建一个列表,这意味着我们想要for p... in pluses for j in range(...)。已更新。
  • 这确实消除了语法错误,但不会导致预期的输出。我将在主要问题中添加一个加号示例供您参考
猜你喜欢
  • 2017-08-20
  • 2020-06-08
  • 2020-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
相关资源
最近更新 更多