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 分支中使用 ifbreak 语句来做到这一点,但我正在研究一些更优化(推荐)的方式如何在 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__)