我喜欢 Peter 的简单回答,尽管它目前是不一样的。我的想法是,您可以通过对 INDICES 进行排序并从后到前执行该过程来摆脱索引移位问题。这导致了 remove_indices1,这确实是低效的。我认为 2 更好,但最简单的是 3,这是 Peter 的答案。
我可能会为一些大数字做一些计时,但我的直觉是,如果 INDICES 非常稀疏,我的 remove_indices2 会比 Peter 的 remove_indices3 快。 (因为您不必遍历每个字符,而只需遍历正在删除的索引。)
顺便说一句 - 如果您可以对 INDICES 进行一次排序,那么您不需要制作本地副本来排序/反转,但我不知道您是否可以这样做。
rows = [
'0000000001111111111222222222233333333334444444444555555555566666666667',
'1234567890123456789012345678901234567890123456789012345678901234567890',
]
def remove_nth_character(row,n):
return row[:n-1] + row[n:]
def remove_indices1(row,indices):
local_indices = indices[:]
retval = row
local_indices.sort()
local_indices.reverse()
for i in local_indices:
retval = remove_nth_character(retval,i)
return retval
def remove_indices2(row,indices):
local_indices = indices[:]
local_indices.sort()
local_indices.reverse()
front = row
chunks = []
for i in local_indices:
chunks.insert(0,front[i:])
front = front[:i-1]
chunks.insert(0,front)
return "".join(chunks)
def remove_indices3(row,indices):
return ''.join(c for i,c in enumerate(row) if i+1 not in indices)
indices = [1,11,4,54,33,20,7]
for row in rows:
print remove_indices1(row,indices)
print ""
for row in rows:
print remove_indices2(row,indices)
print ""
for row in rows:
print remove_indices3(row,indices)
编辑:添加时间信息,以及新的获胜者!
正如我所怀疑的,当要删除的索引不多时,我的算法 (remove_indices2) 会获胜。事实证明,基于枚举的索引会变得更糟,因为要删除的索引更多。这是计时码(bigrows 行有 210000 个字符):
bigrows = []
for row in rows:
bigrows.append(row * 30000)
for indices_len in [10,100,1000,10000,100000]:
print "indices len: %s" % indices_len
indices = range(indices_len)
#for func in [remove_indices1,remove_indices2,remove_indices3,remove_indices4]:
for func in [remove_indices2,remove_indices4]:
start = time.time()
for row in bigrows:
func(row,indices)
print "%s: %s" % (func.__name__,(time.time() - start))
结果如下:
indices len: 10
remove_indices1: 0.0187089443207
remove_indices2: 0.00184297561646
remove_indices3: 1.40601491928
remove_indices4: 0.692481040955
indices len: 100
remove_indices1: 0.0974130630493
remove_indices2: 0.00125503540039
remove_indices3: 7.92742991447
remove_indices4: 0.679095029831
indices len: 1000
remove_indices1: 0.841033935547
remove_indices2: 0.00370812416077
remove_indices3: 73.0718669891
remove_indices4: 0.680690050125
那么,为什么 3 的表现会差这么多呢?好吧,事实证明in 运算符在列表上效率不高。它必须遍历所有要检查的列表项。 remove_indices4 只是 3,但首先将索引转换为集合,因此内部循环可以进行快速哈希查找,而不是遍历列表:
def remove_indices4(row,indices):
indices_set = set(indices)
return ''.join(c for i,c in enumerate(row) if i+1 not in indices_set)
而且,正如我最初预期的那样,这比我的高密度算法更好:
indices len: 10
remove_indices2: 0.00230097770691
remove_indices4: 0.686790943146
indices len: 100
remove_indices2: 0.00113391876221
remove_indices4: 0.665997982025
indices len: 1000
remove_indices2: 0.00296902656555
remove_indices4: 0.700706005096
indices len: 10000
remove_indices2: 0.074893951416
remove_indices4: 0.679219007492
indices len: 100000
remove_indices2: 6.65899395943
remove_indices4: 0.701599836349
如果您要删除的索引少于 10000 个,则 2 是最快的(如果您在函数之外对索引进行排序/反转,则速度会更快)。但是,如果您想要在时间上相当稳定的东西,无论有多少索引,都使用 4。