Python - 从一个列表切换到另一个列表(最佳方式)
Python - switch from one list to another (optimal way)
我有两个列表
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
和一些突破性的 int 值 switchValue = 4
我需要遍历 list1
,而其元素的值小于 switchValue
,然后遍历整个 list2
。我知道如何在 else
分支中使用 if
和 break
语句来做到这一点,但我正在研究一些更优化(推荐)的方式如何在 Python 2.7 中获得它,关于表演,因为这些名单会非常大。此外,列表已排序。
result
应该是 1, 3, 7, 10, 12
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
switchValue = 4
for i in list1:
if i < switchValue:
print(i)
else:
for j in list2:
print(j)
break
for i in list1:
if i >= switchValue:
break
print(i)
for i in list2:
print(i)
这真的是你想要的。遍历 list1
直到找到特定值,然后停止遍历 list1
。然后遍历完整的list2
。这两件事似乎是完全独立的动作,因此没有必要将它们交织在同一个循环中。
请注意,这假设您总是 想要迭代 list2
,而不仅仅是当您遇到 switchValue
时。你的问题在这一点上并不完全清楚。
第一次迭代可以用 itertools.takewhile
:
for i in takewhile(lambda i: i < switchValue, list1):
print(i)
for i in list2:
print(i)
要将两者放入同一个循环中,您可以 chain
它们:
for i in chain(takewhile(lambda i: i < switchValue, list1), list2):
print(i)
您可以使用二进制搜索来查找开关索引:
from bisect import bisect_left
switchIndex = bisect_left(list1, switchValue)
然后在没有 Python 循环的情况下打印(糟糕,在 Python 2 中不起作用,但下面的另一个可以):
print(*list1[:switchIndex], sep='\n')
print(*list2, sep='\n')
或者:
print('\n'.join(map(str, list1[:switchIndex])))
print('\n'.join(map(str, list2)))
在 Python 2 的 100,000 倍长列表中与您和 deceze 一起进行基准测试:
51 ms 52 ms 52 ms Kelly2
137 ms 138 ms 138 ms original
138 ms 138 ms 138 ms deceze1
160 ms 160 ms 161 ms deceze2
164 ms 164 ms 165 ms deceze3
在Python 3:
111 ms 114 ms 114 ms Kelly2
134 ms 134 ms 135 ms Kelly1
176 ms 177 ms 178 ms deceze1
178 ms 178 ms 178 ms original
189 ms 189 ms 191 ms deceze2
191 ms 192 ms 192 ms deceze3
(没有包括@buhtz 的,因为它不太具有可比性。)
基准代码(Try it online! - Python 2 version):
def original():
for i in list1:
if i < switchValue:
print(i)
else:
for j in list2:
print(j)
break
def deceze1():
for i in list1:
if i >= switchValue:
break
print(i)
for i in list2:
print(i)
def deceze2():
for i in takewhile(lambda i: i < switchValue, list1):
print(i)
for i in list2:
print(i)
def deceze3():
for i in chain(takewhile(lambda i: i < switchValue, list1), list2):
print(i)
def Kelly1():
switchIndex = bisect_left(list1, switchValue)
print(*list1[:switchIndex], sep='\n')
print(*list2, sep='\n')
def Kelly2():
switchIndex = bisect_left(list1, switchValue)
print('\n'.join(map(str, list1[:switchIndex])))
print('\n'.join(map(str, list2)))
funcs = original, deceze1, deceze2, deceze3, Kelly1, Kelly2
import os, sys
from timeit import default_timer as timer
from bisect import bisect_left
from itertools import takewhile, chain
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
switchValue = 4
for func in funcs:
print(func.__name__ + ':')
func()
n = 100_000
list1 = [x for x in list1 for _ in range(n)]
list2 = [x for x in list2 for _ in range(n)]
print('benchmark:')
tss = [[] for _ in funcs]
for _ in range(10):
for func, ts in zip(funcs, tss):
with open(os.devnull, 'w') as sys.stdout:
t0 = timer()
func()
t1 = timer()
sys.stdout = sys.__stdout__
ts.append(t1 - t0)
ts.sort()
for func, ts in sorted(zip(funcs, tss), key=lambda x: x[1]):
print(*('%d ms ' % (t * 1e3) for t in sorted(ts)[:3]), func.__name__)
我有两个列表
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
和一些突破性的 int 值 switchValue = 4
我需要遍历 list1
,而其元素的值小于 switchValue
,然后遍历整个 list2
。我知道如何在 else
分支中使用 if
和 break
语句来做到这一点,但我正在研究一些更优化(推荐)的方式如何在 Python 2.7 中获得它,关于表演,因为这些名单会非常大。此外,列表已排序。
result
应该是 1, 3, 7, 10, 12
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
switchValue = 4
for i in list1:
if i < switchValue:
print(i)
else:
for j in list2:
print(j)
break
for i in list1:
if i >= switchValue:
break
print(i)
for i in list2:
print(i)
这真的是你想要的。遍历 list1
直到找到特定值,然后停止遍历 list1
。然后遍历完整的list2
。这两件事似乎是完全独立的动作,因此没有必要将它们交织在同一个循环中。
请注意,这假设您总是 想要迭代 list2
,而不仅仅是当您遇到 switchValue
时。你的问题在这一点上并不完全清楚。
第一次迭代可以用 itertools.takewhile
:
for i in takewhile(lambda i: i < switchValue, list1):
print(i)
for i in list2:
print(i)
要将两者放入同一个循环中,您可以 chain
它们:
for i in chain(takewhile(lambda i: i < switchValue, list1), list2):
print(i)
您可以使用二进制搜索来查找开关索引:
from bisect import bisect_left
switchIndex = bisect_left(list1, switchValue)
然后在没有 Python 循环的情况下打印(糟糕,在 Python 2 中不起作用,但下面的另一个可以):
print(*list1[:switchIndex], sep='\n')
print(*list2, sep='\n')
或者:
print('\n'.join(map(str, list1[:switchIndex])))
print('\n'.join(map(str, list2)))
在 Python 2 的 100,000 倍长列表中与您和 deceze 一起进行基准测试:
51 ms 52 ms 52 ms Kelly2
137 ms 138 ms 138 ms original
138 ms 138 ms 138 ms deceze1
160 ms 160 ms 161 ms deceze2
164 ms 164 ms 165 ms deceze3
在Python 3:
111 ms 114 ms 114 ms Kelly2
134 ms 134 ms 135 ms Kelly1
176 ms 177 ms 178 ms deceze1
178 ms 178 ms 178 ms original
189 ms 189 ms 191 ms deceze2
191 ms 192 ms 192 ms deceze3
(没有包括@buhtz 的,因为它不太具有可比性。)
基准代码(Try it online! - Python 2 version):
def original():
for i in list1:
if i < switchValue:
print(i)
else:
for j in list2:
print(j)
break
def deceze1():
for i in list1:
if i >= switchValue:
break
print(i)
for i in list2:
print(i)
def deceze2():
for i in takewhile(lambda i: i < switchValue, list1):
print(i)
for i in list2:
print(i)
def deceze3():
for i in chain(takewhile(lambda i: i < switchValue, list1), list2):
print(i)
def Kelly1():
switchIndex = bisect_left(list1, switchValue)
print(*list1[:switchIndex], sep='\n')
print(*list2, sep='\n')
def Kelly2():
switchIndex = bisect_left(list1, switchValue)
print('\n'.join(map(str, list1[:switchIndex])))
print('\n'.join(map(str, list2)))
funcs = original, deceze1, deceze2, deceze3, Kelly1, Kelly2
import os, sys
from timeit import default_timer as timer
from bisect import bisect_left
from itertools import takewhile, chain
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
switchValue = 4
for func in funcs:
print(func.__name__ + ':')
func()
n = 100_000
list1 = [x for x in list1 for _ in range(n)]
list2 = [x for x in list2 for _ in range(n)]
print('benchmark:')
tss = [[] for _ in funcs]
for _ in range(10):
for func, ts in zip(funcs, tss):
with open(os.devnull, 'w') as sys.stdout:
t0 = timer()
func()
t1 = timer()
sys.stdout = sys.__stdout__
ts.append(t1 - t0)
ts.sort()
for func, ts in sorted(zip(funcs, tss), key=lambda x: x[1]):
print(*('%d ms ' % (t * 1e3) for t in sorted(ts)[:3]), func.__name__)