我只是想为这两个答案放一些比较时间。
鉴于此基准:
import bisect
import time
def f1(l, tgt):
return bisect.bisect_right(l, tgt)
def f2(l,tgt):
slice_condition = lambda num: num >= tgt
try:
slice_idx = next(idx for idx, num in enumerate(l) if slice_condition(num))
except StopIteration:
slice_idx = len(l)
return slice_idx
def f3(l,tgt):
return next((idx for idx, val in enumerate(l) if val>=tgt), len(l))
def cmpthese(funcs, args=(), cnt=10, rate=True, micro=True, deepcopy=True):
from copy import deepcopy
"""Generate a Perl style function benchmark"""
def pprint_table(table):
"""Perl style table output"""
def format_field(field, fmt='{:,.0f}'):
if type(field) is str: return field
if type(field) is tuple: return field[1].format(field[0])
return fmt.format(field)
def get_max_col_w(table, index):
return max([len(format_field(row[index])) for row in table])
col_paddings=[get_max_col_w(table, i) for i in range(len(table[0]))]
for i,row in enumerate(table):
# left col
row_tab=[row[0].ljust(col_paddings[0])]
# rest of the cols
row_tab+=[format_field(row[j]).rjust(col_paddings[j]) for j in range(1,len(row))]
print(' '.join(row_tab))
results={}
for i in range(cnt):
for f in funcs:
if args:
local_args=deepcopy(args)
start=time.perf_counter_ns()
f(*local_args)
stop=time.perf_counter_ns()
results.setdefault(f.__name__, []).append(stop-start)
results={k:float(sum(v))/len(v) for k,v in results.items()}
fastest=sorted(results,key=results.get, reverse=True)
table=[['']]
if rate: table[0].append('rate/sec')
if micro: table[0].append('\u03bcsec/pass')
table[0].extend(fastest)
for e in fastest:
tmp=[e]
if rate:
tmp.append('{:,}'.format(int(round(float(cnt)*1000000.0/results[e]))))
if micro:
tmp.append('{:,.1f}'.format(results[e]/float(cnt)))
for x in fastest:
if x==e: tmp.append('--')
else: tmp.append('{:.1%}'.format((results[x]-results[e])/results[e]))
table.append(tmp)
pprint_table(table)
if __name__=='__main__':
import sys
print(sys.version)
small=range(1_000)
mid=range(100_000)
large=range(1_000_000)
cases=(
('small, found', small, len(small)//2),
('small, not found', small, len(small)),
('mid, found', mid, len(mid)//2),
('mid, not found', mid, len(mid)),
('large, found', large, len(large)//2),
('large, not found', large, len(large))
)
for txt, x, tgt in cases:
print(f'\n{txt}:')
l=list(x)
args=(l,tgt)
cmpthese([f1,f2,f3],args)
如果您使用小型、中型和大型列表运行它,每个列表都有 1) 在中间找到的情况或 2) 一直扫描到最后,您可以看到 bisect 明显更快。按数量级。
基准打印在我的电脑上:
3.9.1 (default, Jan 30 2021, 15:51:59)
[Clang 12.0.0 (clang-1200.0.32.29)]
small, found:
rate/sec μsec/pass f2 f3 f1
f2 182 5,501.4 -- -59.2% -98.8%
f3 445 2,246.9 144.9% -- -96.9%
f1 14,562 68.7 7911.4% 3172.0% --
small, not found:
rate/sec μsec/pass f2 f3 f1
f2 90 11,053.2 -- -58.8% -99.5%
f3 220 4,555.5 142.6% -- -98.7%
f1 17,349 57.6 19076.4% 7803.3% --
mid, found:
rate/sec μsec/pass f2 f3 f1
f2 2 561,882.8 -- -57.2% -99.9%
f3 4 240,253.2 133.9% -- -99.9%
f1 2,942 339.9 165184.0% 70573.1% --
mid, not found:
rate/sec μsec/pass f2 f3 f1
f2 1 1,119,041.1 -- -58.0% -100.0%
f3 2 469,960.8 138.1% -- -99.9%
f1 3,804 262.9 425552.8% 178660.3% --
large, found:
rate/sec μsec/pass f2 f3 f1
f2 0 5,833,734.0 -- -55.3% -99.9%
f3 0 2,605,010.2 123.9% -- -99.9%
f1 335 2,988.1 195135.5% 87080.9% --
large, not found:
rate/sec μsec/pass f2 f3 f1
f2 0 11,553,311.3 -- -54.4% -100.0%
f3 0 5,264,216.7 119.5% -- -100.0%
f1 710 1,408.9 819923.5% 373540.2% --