I have two lists
list1 = [1, 3, 5, 8]
list2 = [7, 10, 12]
and some breaking int value switchValue = 4
I need to iterate through the list1
while its elements have value smaller than the switchValue
, and after that to iterate through the full list2
. I know how to do it with if
and break
statement in else
branch but I was looking into some more optimal (recommended) way how to get this in Python 2.7, in regards to the performances since these lists will be quite large. Additionally- lists are sorted.
result
should be 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
CodePudding user response:
for i in list1:
if i >= switchValue:
break
print(i)
for i in list2:
print(i)
This is really all you want. Iterate through list1
until you find a specific value, then stop iterating through list1
. Then iterate through the complete list2
. These two things seem to be entirely separate actions, so there's no need to intertwine them in the same loop.
Note that this assumes that you always want to iterate list2
, not only if and when you encountered switchValue
. Your question isn't entirely clear on that point.
The first iteration can be dressed up with things like itertools.takewhile
:
for i in takewhile(lambda i: i < switchValue, list1):
print(i)
for i in list2:
print(i)
To put both into the same loop, you can chain
them:
for i in chain(takewhile(lambda i: i < switchValue, list1), list2):
print(i)
CodePudding user response:
You could use binary search to find the switch index:
from bisect import bisect_left
switchIndex = bisect_left(list1, switchValue)
And then print without a Python loop (oops, doesn't work in Python 2, but the other one below does):
print(*list1[:switchIndex], sep='\n')
print(*list2, sep='\n')
Or:
print('\n'.join(map(str, list1[:switchIndex])))
print('\n'.join(map(str, list2)))
Benchmark along with yours and deceze's on 100,000 times longer lists in Python 2:
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
In 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
(Didn't include @buhtz's because it's not quite comparable.)
Benchmark code (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__)