在正式的 for 循环中使用 else 子句,但在列表理解中,这可能吗?
Use an else clause like the ones in formal for loops but in a list comprehension, is it possible?
这是我的初始列表列表的示例:
trip_chains = [['London', 'Paris', 'Madrid'],
['Delhi', 'London', 'New York'],
...['Jerusalem', 'Cairo', 'Paris']]
我想从 trip_chain 中提取另一个列表,如下所示:
chains_steps = [[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
...[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
所以我使用了一个包含两个 for 循环的列表推导式:
chains_steps = [[chain_[stepscount_], chain_[stepscount_+1]] for chain_ in trip_chains for stepscount_ in range(len(chain_)-1)]
但是因为我失去了返回出发城市的步骤,结果将如下所示:
chains_steps = [[['London', 'Paris'], ['Paris', 'Madrid']],
[['Delhi', 'London'], ['London', 'New York']],
...[['Jerusalem', 'Cairo'], ['Cairo', 'Paris']]]
因为我们可以把这个列表理解看作是一个双重嵌套的for循环,
我们知道 for 循环带有一个可选的 else 子句:
chain_steps = []
for chain_ in trip_chains:
for stepscount_ in range(len(chain_)-1):
chain_steps.append([chain_[stepscount_], chain_[stepscount_+1])
else:
chain_steps.append([chain_[-1], chain_[0]])
我想知道我是否可以这样在 列表理解 中使用这个 else 子句:
chains_steps = [[chain_[stepscount_], chain_[stepscount_+1]] for chain_ in trip_chains for stepscount_ in range(len(chain_)-1) else [chain_[-1], chain_[0]]]
我知道对于这个特定问题可能有很多替代解决方案,但我是出于好奇和知识才问的。
P.S。每次内循环结束后,人们可能想要 运行 一个函数。所以这个问题不是我的例子特有的。
谢谢。
不,您不能在列表理解上有 else
个分支。
您可以循环 chain + [chain[0]]
或使用 %
运算符将步数“折叠”回开头。或者只是手动添加最后一对,正如@mkrieger 在评论中建议的那样。
另一个新答案
基于S.Khajeh'评论,我添加了另一个单行解决方案,即更通用和覆盖有笔画的情况具有不均匀的无限制行程长度
修改为比双重比较更有效 :)
chains_steps = [[[row[i], (row + [row[0]])[i + 1]] for i in range(len(row))] for row in trip_chains]
之前
chains_steps = [[[(row + row)[i], (row + row)[i + 1]] for i in range(len(row))] for row in trip_chains]
旧答案
您也可以通过直接编码如下行来实现您的目标:
chains_steps = [ [ [row[0],row[1]] , [row[1],row[2]] , [row[2],row[0]] ] for row in trip_chains]
输出是
chains_steps
Out[7]:
[[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
如你所愿。
for...else
我建议你学习for...else
语义。 @mkrieger1 的评论可能有点简洁。
doc states:
a loop’s else clause runs when no break occurs.
例如:
>>> for i in range(1):
... print("first and only iteration")
... break
... else: # not executed since there is a break
... print("no break was met")
first and only iteration
但是:
>>> for i in range(1):
... print("first and only iteration")
... else: # executed since the loop exits normally
... print("no break was met")
first and only iteration
no break was met
如果循环体中没有发生 break,则 else 子句总是 运行,
因此以下代码段是等效的:
for ...:
<loop body>
else:
<else statement>
并且:
for ...:
<loop body>
<else statement>
列表的列表还是列表的列表?
你写:
chain_steps = []
for chain_ in trip_chains:
for stepscount_ in range(len(chain_)-1):
chain_steps.append([chain_[stepscount_], chain_[stepscount_+1]])
else:
chain_steps.append([chain_[-1], chain_[0]])
正如@Ture Pålsson 所写,这只会产生一个列表列表。正确的版本是:
trip_chains = [['London', 'Paris', 'Madrid'],
['Delhi', 'London', 'New York'],
['Jerusalem', 'Cairo', 'Paris']]
chain_steps = []
for chain_ in trip_chains:
chain_step = [] # create a new list in the outer loop
# and fill it in the inner loop
for stepscount_ in range(len(chain_)-1):
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
chain_step.append([chain_[-1], chain_[0]])
chain_steps.append(chain_step)
from pprint import pprint
pprint(chain_steps)
输出:
[[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
不需要“初等数学”。
我们可以在列表理解中添加 else
子句吗?
主要问题是:我们可以在列表理解中使用 break
吗?答案是否定的(Python 3):
>>> [i if i<5 else break for i in range(10)]
Traceback (most recent call last):
[i if i<5 else break for i in range(10)]
^
SyntaxError: invalid syntax
(有关详细信息,请参阅 Using break in a list comprehension)。
因此,else
子句在列表理解中没有意义。结果:我们不能在列表理解中有 else
子句。
我们可以在列表理解中添加额外的元素吗?
我将重点介绍内循环:
chain_ = ['London', 'Paris', 'Madrid']
chain_step = []
for stepscount_ in range(len(chain_)-1):
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
chain_step.append([chain_[-1], chain_[0]]) # extra element
pprint(chain_step)
输出:
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
显然,我们可以用最后一个元素添加一个迭代:
chain_step = []
for stepscount_ in list(range(len(chain_)-1))+[-1]:
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
然后:
>>> chain_ = ['London', 'Paris', 'Madrid']
>>> [[chain_[s], chain_[s+1]] for s in list(range(len(chain_)-1))+[-1]]
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
当你可以这样写时,这有点矫枉过正:
>>> chain_ = ['London', 'Paris', 'Madrid']
>>> [[chain_[s], chain_[s+1]] for s in range(len(chain_)-1)] + [[chain_[-1], chain_[0]]]
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
(您可以轻松地将其包装在外部列表理解中:
chain_steps = [
[[chain_[s], chain_[s+1]] for s in range(len(chain_)-1)] + [[chain_[-1], chain_[0]]]
for chain_ in trip_chains
]
)
奖金:有没有更简洁的方式来写这个?
YES(内循环):
chain_step = []
for step in zip(chain_, chain_[1:]+[chain_[0]]):
chain_step.append(step)
pprint(chain_step)
输出:
[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')]
zip
函数将对元素进行配对:
chain[0], chain[1], ... chain_[n-2], chain_[n-1] <- chain_
chain[1], chain[2], ... chain_[n-1], chain_[0] <- chain_[1:]+[chain_[0]]
如您所见,您有一个元组列表,而不是列表列表。这样更好,因为一个步骤是一对,而不是一个列表(元组大小不会改变,列表大小可能会改变)。
因此最终的双列表理解:
>>> trip_chains = [['London', 'Paris', 'Madrid'],
... ['Delhi', 'London', 'New York'],
... ['Jerusalem', 'Cairo', 'Paris']]
>>> [[step for step in zip(chain_, chain_[1:]+[chain_[0]])] for chain_ in trip_chains]
[[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')], [('Delhi', 'London'), ('London', 'New York'), ('New York', 'Delhi')], [('Jerusalem', 'Cairo'), ('Cairo', 'Paris'), ('Paris', 'Jerusalem')]]
或者,因为内部列表推导式只取 zip
:
的元素
>>> [list(zip(chain_, chain_[1:]+[chain_[0]])) for chain_ in trip_chains]
[[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')], [('Delhi', 'London'), ('London', 'New York'), ('New York', 'Delhi')], [('Jerusalem', 'Cairo'), ('Cairo', 'Paris'), ('Paris', 'Jerusalem')]]
注意:代码变得难以维护...
这是我的初始列表列表的示例:
trip_chains = [['London', 'Paris', 'Madrid'],
['Delhi', 'London', 'New York'],
...['Jerusalem', 'Cairo', 'Paris']]
我想从 trip_chain 中提取另一个列表,如下所示:
chains_steps = [[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
...[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
所以我使用了一个包含两个 for 循环的列表推导式:
chains_steps = [[chain_[stepscount_], chain_[stepscount_+1]] for chain_ in trip_chains for stepscount_ in range(len(chain_)-1)]
但是因为我失去了返回出发城市的步骤,结果将如下所示:
chains_steps = [[['London', 'Paris'], ['Paris', 'Madrid']],
[['Delhi', 'London'], ['London', 'New York']],
...[['Jerusalem', 'Cairo'], ['Cairo', 'Paris']]]
因为我们可以把这个列表理解看作是一个双重嵌套的for循环, 我们知道 for 循环带有一个可选的 else 子句:
chain_steps = []
for chain_ in trip_chains:
for stepscount_ in range(len(chain_)-1):
chain_steps.append([chain_[stepscount_], chain_[stepscount_+1])
else:
chain_steps.append([chain_[-1], chain_[0]])
我想知道我是否可以这样在 列表理解 中使用这个 else 子句:
chains_steps = [[chain_[stepscount_], chain_[stepscount_+1]] for chain_ in trip_chains for stepscount_ in range(len(chain_)-1) else [chain_[-1], chain_[0]]]
我知道对于这个特定问题可能有很多替代解决方案,但我是出于好奇和知识才问的。
P.S。每次内循环结束后,人们可能想要 运行 一个函数。所以这个问题不是我的例子特有的。
谢谢。
不,您不能在列表理解上有 else
个分支。
您可以循环 chain + [chain[0]]
或使用 %
运算符将步数“折叠”回开头。或者只是手动添加最后一对,正如@mkrieger 在评论中建议的那样。
另一个新答案
基于S.Khajeh'评论,我添加了另一个单行解决方案,即更通用和覆盖有笔画的情况具有不均匀的无限制行程长度
修改为比双重比较更有效 :)
chains_steps = [[[row[i], (row + [row[0]])[i + 1]] for i in range(len(row))] for row in trip_chains]
之前
chains_steps = [[[(row + row)[i], (row + row)[i + 1]] for i in range(len(row))] for row in trip_chains]
旧答案
您也可以通过直接编码如下行来实现您的目标:
chains_steps = [ [ [row[0],row[1]] , [row[1],row[2]] , [row[2],row[0]] ] for row in trip_chains]
输出是
chains_steps
Out[7]:
[[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
如你所愿。
for...else
我建议你学习for...else
语义。 @mkrieger1 的评论可能有点简洁。
doc states:
a loop’s else clause runs when no break occurs.
例如:
>>> for i in range(1):
... print("first and only iteration")
... break
... else: # not executed since there is a break
... print("no break was met")
first and only iteration
但是:
>>> for i in range(1):
... print("first and only iteration")
... else: # executed since the loop exits normally
... print("no break was met")
first and only iteration
no break was met
如果循环体中没有发生 break,则 else 子句总是 运行, 因此以下代码段是等效的:
for ...:
<loop body>
else:
<else statement>
并且:
for ...:
<loop body>
<else statement>
列表的列表还是列表的列表?
你写:
chain_steps = []
for chain_ in trip_chains:
for stepscount_ in range(len(chain_)-1):
chain_steps.append([chain_[stepscount_], chain_[stepscount_+1]])
else:
chain_steps.append([chain_[-1], chain_[0]])
正如@Ture Pålsson 所写,这只会产生一个列表列表。正确的版本是:
trip_chains = [['London', 'Paris', 'Madrid'],
['Delhi', 'London', 'New York'],
['Jerusalem', 'Cairo', 'Paris']]
chain_steps = []
for chain_ in trip_chains:
chain_step = [] # create a new list in the outer loop
# and fill it in the inner loop
for stepscount_ in range(len(chain_)-1):
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
chain_step.append([chain_[-1], chain_[0]])
chain_steps.append(chain_step)
from pprint import pprint
pprint(chain_steps)
输出:
[[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']],
[['Delhi', 'London'], ['London', 'New York'], ['New York', 'Delhi']],
[['Jerusalem', 'Cairo'], ['Cairo', 'Paris'], ['Paris', 'Jerusalem']]]
不需要“初等数学”。
我们可以在列表理解中添加 else
子句吗?
主要问题是:我们可以在列表理解中使用 break
吗?答案是否定的(Python 3):
>>> [i if i<5 else break for i in range(10)]
Traceback (most recent call last):
[i if i<5 else break for i in range(10)]
^
SyntaxError: invalid syntax
(有关详细信息,请参阅 Using break in a list comprehension)。
因此,else
子句在列表理解中没有意义。结果:我们不能在列表理解中有 else
子句。
我们可以在列表理解中添加额外的元素吗?
我将重点介绍内循环:
chain_ = ['London', 'Paris', 'Madrid']
chain_step = []
for stepscount_ in range(len(chain_)-1):
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
chain_step.append([chain_[-1], chain_[0]]) # extra element
pprint(chain_step)
输出:
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
显然,我们可以用最后一个元素添加一个迭代:
chain_step = []
for stepscount_ in list(range(len(chain_)-1))+[-1]:
chain_step.append([chain_[stepscount_], chain_[stepscount_+1]])
然后:
>>> chain_ = ['London', 'Paris', 'Madrid']
>>> [[chain_[s], chain_[s+1]] for s in list(range(len(chain_)-1))+[-1]]
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
当你可以这样写时,这有点矫枉过正:
>>> chain_ = ['London', 'Paris', 'Madrid']
>>> [[chain_[s], chain_[s+1]] for s in range(len(chain_)-1)] + [[chain_[-1], chain_[0]]]
[['London', 'Paris'], ['Paris', 'Madrid'], ['Madrid', 'London']]
(您可以轻松地将其包装在外部列表理解中:
chain_steps = [
[[chain_[s], chain_[s+1]] for s in range(len(chain_)-1)] + [[chain_[-1], chain_[0]]]
for chain_ in trip_chains
]
)
奖金:有没有更简洁的方式来写这个?
YES(内循环):
chain_step = []
for step in zip(chain_, chain_[1:]+[chain_[0]]):
chain_step.append(step)
pprint(chain_step)
输出:
[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')]
zip
函数将对元素进行配对:
chain[0], chain[1], ... chain_[n-2], chain_[n-1] <- chain_
chain[1], chain[2], ... chain_[n-1], chain_[0] <- chain_[1:]+[chain_[0]]
如您所见,您有一个元组列表,而不是列表列表。这样更好,因为一个步骤是一对,而不是一个列表(元组大小不会改变,列表大小可能会改变)。
因此最终的双列表理解:
>>> trip_chains = [['London', 'Paris', 'Madrid'],
... ['Delhi', 'London', 'New York'],
... ['Jerusalem', 'Cairo', 'Paris']]
>>> [[step for step in zip(chain_, chain_[1:]+[chain_[0]])] for chain_ in trip_chains]
[[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')], [('Delhi', 'London'), ('London', 'New York'), ('New York', 'Delhi')], [('Jerusalem', 'Cairo'), ('Cairo', 'Paris'), ('Paris', 'Jerusalem')]]
或者,因为内部列表推导式只取 zip
:
>>> [list(zip(chain_, chain_[1:]+[chain_[0]])) for chain_ in trip_chains]
[[('London', 'Paris'), ('Paris', 'Madrid'), ('Madrid', 'London')], [('Delhi', 'London'), ('London', 'New York'), ('New York', 'Delhi')], [('Jerusalem', 'Cairo'), ('Cairo', 'Paris'), ('Paris', 'Jerusalem')]]
注意:代码变得难以维护...