[英]Find index for multiple elements in a long list
我有一个很长的lst
包含独特的元素。 我想设计一个以元素列表作为输入的函数,它可以有效地返回索引列表。 我们假设查找索引所需的项目都在lst
。
下面是一个例子:
lst = ['ab','sd','ef','de']
items_to_find = ['sd', 'ef', 'sd']
>>> fo(lst, items_to_find)
# Output: [1,2,1]
我有自己的一种解决方案,但它看起来效率较低。
>> [lst.index(x) for x in items_to_find]
因为lst
很长,我需要一个非常快的算法来解决它。
首先创建一个字典,其中包含列表中每个项目的索引位置(您声明所有项目都是唯一的,因此没有重复键的问题)。
然后使用字典查找每个项目的索引位置,平均时间复杂度为 O(1)。
my_list = ['ab', 'sd', 'ef', 'de']
d = {item: idx for idx, item in enumerate(my_list)}
items_to_find = ['sd', 'ef', 'sd']
>>> [d.get(item) for item in items_to_find]
[1, 2, 1]
您可以使用以 lst 中的元素作为键、索引和值的字典。 在字典中搜索是 O(1)。
尽管您接受的答案非常好,但这里有一些内存效率更高的方法,并且速度可能几乎一样快。 但是,如果列表很长(因为其中的元素都是唯一的),@Alexander 的回答会创建一个潜在的巨大字典。
下面的代码还构建了一个字典来加速搜索,但它是针对目标元素的,因此可能比正在搜索的列表小得多。 对于它创建的示例数据(命名为targets
)仅包含: {'sd': [0, 2], 'ef': [1]}
它会遍历序列并检查其中的每个值是否为目标,如果是,则更新结果列表。 这种方法需要更多的代码来实现,因为设置稍微涉及更多,所以这是另一个权衡。
def find_indices(seq, elements):
targets = {}
for index, element in enumerate(elements):
targets.setdefault(element, []).append(index)
indices = [None for _ in elements] # Pre-allocate.
for location, value in enumerate(seq):
if value in targets:
for element, indexes in targets.items():
if element == value:
for index in indexes:
indices[index] = location
return indices
lst = ['ab', 'sd', 'ef', 'de']
indices = find_indices(lst, ['sd', 'ef', 'sd'])
print(indices) # -> [1, 2, 1]
一个简单的一阶近似...
def get_indices(data_list, query_list):
datum_index_mapping = {datum:None for datum in query_list}
for index, datum in enumerate(data_list):
if datum in datum_index_mapping:
datum_index_mapping[datum] = index
return [datum_index_mapping[d] for d in query_list]
以上是最简单、直观的解决方案,它使一些努力变得高效(只需费心存储您实际想要查找的元素的索引字典)。
然而,它受到这样一个事实的影响——即使初始查询列表非常短——它也会遍历整个数据列表/数据生成器。 此外,每次看到之前看到的值时,它都必须进行字典写入。 下面修复了这些低效率,尽管它增加了集合的开销,因此它必须为查询列表中的每个唯一元素执行集合写入,以及为查询列表中的每个唯一元素执行字典写入。
def get_indices(data_list, query_list):
not_found = set(query_list)
datum_index_mapping = {}
for index, datum in enumerate(data_list):
if datum in not_found:
datum_index_mapping[datum] = index
not_found.remove(datum)
if len(not_found) == 0:
break
return [datum_index_mapping[d] for d in query_list]
显然,根据您的程序,您实际上可能根本不想拥有索引列表,而只是让您的函数返回映射。 如果您要解析多个任意查询列表,您可能只想在原始数据集上执行enumerate()
,如其他答案所示,并将将值映射到内存中的索引的字典以及用于查询目的。
什么算有效率通常取决于更大的程序; 我们在这里所能做的就是鸽巢优化。 它还取决于内存层次结构和处理能力(即我们可以并行化吗?计算更昂贵,还是内存更昂贵?如果我们需要回退到交换,I/O 命中率是多少?)。
如果您确定搜索列表中确实存在所有搜索到的值,并且对 lst 进行了排序(当然,排序本身可能需要一些时间),则可以一次性完成(线性复杂度):
def sortedindex(lst,find):
find.sort()
indices = []
start = 0
for item in find:
start = lst.index(item,start)
indices.append(start)
return indices
“开始”显示算法开始将检查的项目与主列表中的项目进行比较的第一个索引。 当找到正确的索引时,它将成为下一个起始标记。 由于两个列表的排序方式相同,因此您不必担心跳过任何下一个项目。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.