用 break 列出推导式
list comprehensions with break
我有以下代码,我想用列表理解写在一行中。
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]
list3 = []
for i in list1:
for j in list2:
if j>i:
# print(i,j)
list3.append(j)
break
print(list1)
print(list3)
输出为:
[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
是 break 语句让我失望,我不知道该把它放在哪里。
谢谢
要构建表达式,首先忽略 break
条件:
In [32]: [[j for j in list2 if j > i] for i in list1]
Out[32]:
[[5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[17, 20, 24, 26, 56],
[24, 26, 56],
[24, 26, 56],
[26, 56],
[56]]
从那里您可以添加 min
约束:
In [33]: [min([j for j in list2 if j > i]) for i in list1]
Out[33]: [5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
我已经尝试计时 AbbeGijly 发布的答案。
事实证明,它比原来的解决方案慢。看看吧。
import timeit
print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]
list3 = []
for i in list1:
for j in list2:
if j>i:
# print(i,j)
list3.append(j)
break
'''))
print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]
list4 = [[j for j in list2 if j > i] for i in list1]
'''))
输出为:
3.6144596
8.731578200000001
您可以将 break 逻辑移动到一个单独的函数中,然后将该函数放入列表理解中:
def smallest_value_larger_than_i(candidate_values, i):
for value in candidate_values:
if value > i:
return value
return None # Not sure how you want to handle this case
list3 = [smallest_value_larger_than_i(list2, i) for i in list1]
这比您的原始解决方案运行速度稍慢,但如果使用列表推导式的目标是提高速度,那么您可以通过改进算法来获得更好的结果。例如,如果两个列表都已排序,那么您可以在跳过一次后立即丢弃 list2 中的元素,而不是将它们与 list1 的其余部分进行检查。您也可以对 list2 进行二进制搜索,而不是线性扫描它。
你不能真正打破列表理解的内部 for 循环,你可以做的是通过使用 next 函数找到匹配值的第一次出现来避免必须打破它:
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]
list3 = [ next(j for j in list2 if j>i) for i in list1 ]
输出:
print(list1)
print(list3)
[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
如果您担心性能(因为列表理解会比循环慢),您可以在列表 2 中使用二等分搜索来查找下一个更高的值:
from bisect import bisect_left
list3 = [ list2[bisect_left(list2,i+1)] for i in list1 ]
这假设 list2 按升序排序并且 max(list2) > max(list1)
我有以下代码,我想用列表理解写在一行中。
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]
list3 = []
for i in list1:
for j in list2:
if j>i:
# print(i,j)
list3.append(j)
break
print(list1)
print(list3)
输出为:
[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
是 break 语句让我失望,我不知道该把它放在哪里。
谢谢
要构建表达式,首先忽略 break
条件:
In [32]: [[j for j in list2 if j > i] for i in list1]
Out[32]:
[[5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[11, 12, 13, 14, 15, 17, 20, 24, 26, 56],
[17, 20, 24, 26, 56],
[24, 26, 56],
[24, 26, 56],
[26, 56],
[56]]
从那里您可以添加 min
约束:
In [33]: [min([j for j in list2 if j > i]) for i in list1]
Out[33]: [5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
我已经尝试计时 AbbeGijly 发布的答案。
事实证明,它比原来的解决方案慢。看看吧。
import timeit
print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]
list3 = []
for i in list1:
for j in list2:
if j>i:
# print(i,j)
list3.append(j)
break
'''))
print(timeit.timeit('''
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 40, 56]
list4 = [[j for j in list2 if j > i] for i in list1]
'''))
输出为:
3.6144596
8.731578200000001
您可以将 break 逻辑移动到一个单独的函数中,然后将该函数放入列表理解中:
def smallest_value_larger_than_i(candidate_values, i):
for value in candidate_values:
if value > i:
return value
return None # Not sure how you want to handle this case
list3 = [smallest_value_larger_than_i(list2, i) for i in list1]
这比您的原始解决方案运行速度稍慢,但如果使用列表推导式的目标是提高速度,那么您可以通过改进算法来获得更好的结果。例如,如果两个列表都已排序,那么您可以在跳过一次后立即丢弃 list2 中的元素,而不是将它们与 list1 的其余部分进行检查。您也可以对 list2 进行二进制搜索,而不是线性扫描它。
你不能真正打破列表理解的内部 for 循环,你可以做的是通过使用 next 函数找到匹配值的第一次出现来避免必须打破它:
list1 = [4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
list2 = [1, 3, 5, 7, 8, 11, 12, 13, 14, 15, 17, 20, 24, 26, 56]
list3 = [ next(j for j in list2 if j>i) for i in list1 ]
输出:
print(list1)
print(list3)
[4, 5, 6, 9, 10, 16, 21, 23, 25, 27]
[5, 7, 7, 11, 11, 17, 24, 24, 26, 56]
如果您担心性能(因为列表理解会比循环慢),您可以在列表 2 中使用二等分搜索来查找下一个更高的值:
from bisect import bisect_left
list3 = [ list2[bisect_left(list2,i+1)] for i in list1 ]
这假设 list2 按升序排序并且 max(list2) > max(list1)