1

说,为了演示,我必须列出“输入点”,并输出从这些点开始的三对数字:

1 -> [(1, 2), (3, 4), (5, 6)]
12 -> [(12, 13), (14, 15), (16, 17)]
...

我可以在扩展的 for 循环中做到这一点:

points = [1, 12, 42, 69]  # arbitrary inputs
result = []
for point in points:
    rng = range(points, points + 6)
    pairs = list(zip(rng[::2], rng[1::2]))
    result.append(pairs)
return result

我还可以通过列表理解更简洁地做到这一点,使用海象运算符来避免range()一遍又一遍地调用:

points = [1, 12, 42, 69]
result = [
             list(zip((y := range(p, p + 6))[::2], y[1::2]))
             for p in startpoints
         ]

但是,如果我想使用列表推导而不是list(),并进一步处理zip()(例如,将我的输出作为字符串)的结果,我不能这样做:

points = [1, 12, 42, 69]
result = [
             [
                 str(tup) 
                 for tup in zip((y := range(p, p + 6))[::2], y[1::2])
             ]
             for p in startpoints
         ]
# produces the following error:
  File "<stdin>", line 4
SyntaxError: assignment expression cannot be used in a comprehension iterable expression

PEP 572提到实现赋值运算符的问题是其根源:

由于参考实现中的设计限制(符号表分析器无法轻易检测到名称何时在最左边的理解可迭代表达式和理解的其余部分之间重用),命名表达式完全不允许作为理解可迭代表达式的一部分(部分在每个“in”之后,以及任何后续“if”或“for”关键字之前)

这让我失望。除了将其扩展为完整for循环之外,是否有任何解决方法?

4

1 回答 1

0

这样做的经典方法是:

[
  [tup for y in [range(p, p + 6)] for tup in zip(y[::2], y[1::2])]
  for p in points
]

然而,这相当难看(并且需要为每个 p 构建额外的列表/元组)。

您可以通过以下方式避免整个范围/压缩:

[[(y, y + 1) for y in range(p, p + 6, 2)] for p in points]

我相信这使它更具可读性(并且速度也稍快一些,因为它避免了 zip 和每个 p 的 3 个范围调用中的 2 个)。

于 2020-11-29T23:16:37.213 回答