获取接近列表末尾的元素索引
Getting index of element close to end of list
我有一个包含 objects 的排序列表,我想获取最后一个值的第一个索引(使用 get_val 方法)的列表。我写了这个函数,但我想知道是否有任何方法可以进一步优化它?
def index_last_value(tbl, get_val=lambda obj:obj):
tbl_len, prev_v = len(tbl), get_val(tbl[-1])
for i,v in enumerate(reversed(tbl)):
v = get_val(v)
if v == prev_v:
index = tbl_len-i-1
if v != prev_v or i+1 == tbl_len:
return index
prev_v = v
class MyObject:
def __init__(self, v):
self.v = v
tbl_1 = list(map(MyObject, [1,1]))
tbl_2 = list(map(MyObject, [1,1,2,2,2]))
index_last_value(tbl_1, get_val=lambda obj:obj.v) # -> 0
index_last_value(tbl_2, get_val=lambda obj:obj.v) # -> 2
编辑:列表不包含数字,它包含对象。
一般回答
我们从头到尾扫描列表
def index_last_value(tbl, get_val=lambda obj:obj):
lastv = get_val(tbl[-1])
for i,v in enumerate(tbl):
if get_val(v) == lastv:
return i
特例:值是连续的(即没有间隙):
[1, 1, 2, 2, 2] 是可能的,[1, 1, 2, 3, 2] 不是。
我们从头到尾扫描列表,
我们可以反转列表,但我们也可以不反转它:
def index_last_value(tbl, get_val=lambda obj:obj):
len_tbl = len(tbl)
if len_tbl == 1:
return 0
lastv = get_val(tbl[-1])
for i,v in enumerate(tbl[-2::-1]):
if get_val(v) != lastv:
return len_tbl - i - 1
return 0
这快了约 33%(对于给定的数据):
def index_last_value2(tbl, get_val=lambda obj:obj):
prev_v = get_val(tbl[-1])
for i in range(len(tbl) - 2, -1, -1):
if get_val(tbl[i]) != prev_v:
return i + 1
return 0
通过将参数 get_val
函数更改为属性名称,您可以获得另外 ~15% 的 speepdup:
def index_last_value3(tbl, val_name):
prev_v = tbl[-1].__dict__[val_name]
for i in range(len(tbl) - 2, -1, -1):
if tbl[i].__dict__[val_name] != prev_v:
return i + 1
return 0
index_last_value3(tbl_1, val_name='v')
index_last_value3(tbl_2, val_name='v')
以相反的顺序分析以确保 RAM 操作不支持优化版本:
44 1001 2682.0 2.7 3.8 for _ in range(1000):
45 1000 6420.0 6.4 9.1 index_last_value3(tbl_1, val_name='v')
46 1000 7857.0 7.9 11.1 index_last_value3(tbl_2, val_name='v')
47 1001 2745.0 2.7 3.9 for _ in range(1000):
48 1000 7676.0 7.7 10.9 index_last_value2(tbl_1, get_val=lambda obj: obj.v)
49 1000 10370.0 10.4 14.7 index_last_value2(tbl_2, get_val=lambda obj:obj.v)
50 1001 2670.0 2.7 3.8 for _ in range(1000):
51 1000 12083.0 12.1 17.1 index_last_value(tbl_1, get_val=lambda obj: obj.v)
52 1000 18007.0 18.0 25.5 index_last_value(tbl_2, get_val=lambda obj: obj.v)
我有一个包含 objects 的排序列表,我想获取最后一个值的第一个索引(使用 get_val 方法)的列表。我写了这个函数,但我想知道是否有任何方法可以进一步优化它?
def index_last_value(tbl, get_val=lambda obj:obj):
tbl_len, prev_v = len(tbl), get_val(tbl[-1])
for i,v in enumerate(reversed(tbl)):
v = get_val(v)
if v == prev_v:
index = tbl_len-i-1
if v != prev_v or i+1 == tbl_len:
return index
prev_v = v
class MyObject:
def __init__(self, v):
self.v = v
tbl_1 = list(map(MyObject, [1,1]))
tbl_2 = list(map(MyObject, [1,1,2,2,2]))
index_last_value(tbl_1, get_val=lambda obj:obj.v) # -> 0
index_last_value(tbl_2, get_val=lambda obj:obj.v) # -> 2
编辑:列表不包含数字,它包含对象。
一般回答
我们从头到尾扫描列表
def index_last_value(tbl, get_val=lambda obj:obj):
lastv = get_val(tbl[-1])
for i,v in enumerate(tbl):
if get_val(v) == lastv:
return i
特例:值是连续的(即没有间隙): [1, 1, 2, 2, 2] 是可能的,[1, 1, 2, 3, 2] 不是。
我们从头到尾扫描列表,
我们可以反转列表,但我们也可以不反转它:
def index_last_value(tbl, get_val=lambda obj:obj):
len_tbl = len(tbl)
if len_tbl == 1:
return 0
lastv = get_val(tbl[-1])
for i,v in enumerate(tbl[-2::-1]):
if get_val(v) != lastv:
return len_tbl - i - 1
return 0
这快了约 33%(对于给定的数据):
def index_last_value2(tbl, get_val=lambda obj:obj):
prev_v = get_val(tbl[-1])
for i in range(len(tbl) - 2, -1, -1):
if get_val(tbl[i]) != prev_v:
return i + 1
return 0
通过将参数 get_val
函数更改为属性名称,您可以获得另外 ~15% 的 speepdup:
def index_last_value3(tbl, val_name):
prev_v = tbl[-1].__dict__[val_name]
for i in range(len(tbl) - 2, -1, -1):
if tbl[i].__dict__[val_name] != prev_v:
return i + 1
return 0
index_last_value3(tbl_1, val_name='v')
index_last_value3(tbl_2, val_name='v')
以相反的顺序分析以确保 RAM 操作不支持优化版本:
44 1001 2682.0 2.7 3.8 for _ in range(1000):
45 1000 6420.0 6.4 9.1 index_last_value3(tbl_1, val_name='v')
46 1000 7857.0 7.9 11.1 index_last_value3(tbl_2, val_name='v')
47 1001 2745.0 2.7 3.9 for _ in range(1000):
48 1000 7676.0 7.7 10.9 index_last_value2(tbl_1, get_val=lambda obj: obj.v)
49 1000 10370.0 10.4 14.7 index_last_value2(tbl_2, get_val=lambda obj:obj.v)
50 1001 2670.0 2.7 3.8 for _ in range(1000):
51 1000 12083.0 12.1 17.1 index_last_value(tbl_1, get_val=lambda obj: obj.v)
52 1000 18007.0 18.0 25.5 index_last_value(tbl_2, get_val=lambda obj: obj.v)