Python 确定有序子列表是否位于大型列表中的最快方法?
假设我有一个巨大的列表,其中包含2000000个列表,每个列表的长度约为50 我想通过丢弃序列中不包含两个元素的子列表来缩短2000000个Python 确定有序子列表是否位于大型列表中的最快方法?,python,list,nested-lists,Python,List,Nested Lists,假设我有一个巨大的列表,其中包含2000000个列表,每个列表的长度约为50 我想通过丢弃序列中不包含两个元素的子列表来缩短2000000个我的\u庞大的\u列表 到目前为止,我已经: # https://stackoverflow.com/questions/3313590/check-for-presence-of-a-sliced-list-in-python def check_if_list_is_sublist(lst, sublst): #checks if a list
我的\u庞大的\u列表
到目前为止,我已经:
# https://stackoverflow.com/questions/3313590/check-for-presence-of-a-sliced-list-in-python
def check_if_list_is_sublist(lst, sublst):
#checks if a list appears in order in another larger list.
n = len(sublst)
return any((sublst == lst[i:i + n]) for i in xrange(len(lst) - n + 1))
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not check_if_list_is_sublist(x, [a,b])]
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not check_if_list_is_sublist(x, [b,a])]
搜索词[a,b]或[b,a]的连续性很重要,因此我不能使用set.issubset()
我觉得这很慢。我想加快速度。我考虑了一些选项,如使用“提前退出”和声明:
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if (a in x and not check_if_list_is_sublist(x, [a,b]))]
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not (check_if_list_is_sublist(x, [a,b])
or check_if_list_is_sublist(x, [b,a]))]
使用或
语句的for
循环中的次数更少:
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if (a in x and not check_if_list_is_sublist(x, [a,b]))]
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not (check_if_list_is_sublist(x, [a,b])
or check_if_list_is_sublist(x, [b,a]))]
并致力于加速功能(WIP)
并对堆栈溢出进行了搜索;但是想不出办法,因为调用check\u if\u list\u is\u sublist()
的次数是len(我的庞大列表)*2
编辑:根据请求添加一些用户数据
from random import randint
from string import ascii_lowercase
my_huge_list_of_lists = [[ascii_lowercase[randint(0, 25)] for x in range(50)] for y in range(2000000)]
my_neighbor_search_fwd = [i,c]
my_neighbor_search_rev = my_neighbor_search_fwd.reverse()
将n大小的子序列中的项解包为n个变量。然后写一个列表理解来过滤列表,检查子列表中的a、b或b、a
将n大小的子序列中的项解包为n个变量。然后写一个列表理解来过滤列表,检查子列表中的a、b或b、a
所以,我想不出任何聪明的算法检查来真正减少这里的工作量。但是,您在代码中执行了大量分配,并且迭代太多。所以,仅仅把一些声明移出函数就有点让我抓狂了
sublst = [a, b]
l = len(sublst)
indices = range(len(sublst))
def check_if_list_is_sublist(lst):
for i in range(len(lst) - (l -1)):
if lst[i] == sublst[0] and lst[i+1] == sublst[1]:
return True
if lst[i] == sublst[1] and lst[i + 1] == sublst[0]:
return True
return False
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not check_if_list_is_sublist(x)]
这将上述示例代码的运行时间减少了约50%。有了这么大的列表,产生更多的进程并划分工作可能会看到性能的提高。但是,我想不出任何方法来真正减少比较量…因此,我想不出任何聪明的算法检查来真正减少工作量。但是,您在代码中执行了大量分配,并且迭代太多。所以,仅仅把一些声明移出函数就有点让我抓狂了
sublst = [a, b]
l = len(sublst)
indices = range(len(sublst))
def check_if_list_is_sublist(lst):
for i in range(len(lst) - (l -1)):
if lst[i] == sublst[0] and lst[i+1] == sublst[1]:
return True
if lst[i] == sublst[1] and lst[i + 1] == sublst[0]:
return True
return False
my_huge_list_of_lists = [x for x in my_huge_list_of_lists
if not check_if_list_is_sublist(x)]
这将上述示例代码的运行时间减少了约50%。有了这么大的列表,产生更多的进程并划分工作可能会看到性能的提高。我想不出任何方法来真正减少比较的数量,尽管…对于一个大列表中的搜索匹配,我相信哈希(元素)然后构建索引将是一个很好的解决方案
您将获得的好处:
构建索引一次,节省时间供将来使用(无需为每次搜索重复循环)。
甚至,我们可以在启动程序时建立索引,然后在程序退出时释放它
下面的代码使用两种方法获取哈希值:hash()和str();有时,您应该根据特定场景自定义一个哈希函数
如果使用Stand(),代码看起来很简单,不需要考虑哈希冲突。但这可能会导致内存爆炸
对于hash(),我使用该列表保存所有具有相同hash值的sub_lst。您可以使用hash(sub_lst)%designed_length来控制hash大小(但它会增加hash冲突率)
以下代码的输出:
按散列:0.0002398660394852955
按str():0.00022884208565612796
按OP编号:0.3001317172469765
[以1.781s完成]
测试代码:
from random import randint
from string import ascii_lowercase
import timeit
#Generate Test Data
my_huge_list_of_lists = [[ascii_lowercase[randint(0, 25)] for x in range(50)] for y in range(10000)]
#print(my_huge_list_of_lists)
test_lst = [['a', 'b', 'c' ], ['a', 'b', 'c'] ]
#Solution 1: By using built-in hash function
def prepare1(huge_list, interval=1): #use built-in hash function
hash_db = {}
for index in range(len(huge_list) - interval + 1):
hash_sub = hash(str(huge_list[index:index+interval]))
if hash_sub in hash_db:
hash_db[hash_sub].append(huge_list[index:index+interval])
else:
hash_db[hash_sub] = [huge_list[index:index+interval]]
return hash_db
hash_db = prepare1(my_huge_list_of_lists, interval=2)
def check_sublist1(hash_db, sublst): #use built-in hash function
hash_sub = hash(str(sublst))
if hash_sub in hash_db:
return any([sublst == item for item in hash_db[hash_sub]])
return False
print('By Hash:', timeit.timeit("check_sublist1(hash_db, test_lst)", setup="from __main__ import check_sublist1, my_huge_list_of_lists, test_lst, hash_db ", number=100))
#Solution 2: By using str() as hash function
def prepare2(huge_list, interval=1): #use str() as hash function
return { str(huge_list[index:index+interval]):huge_list[index:index+interval] for index in range(len(huge_list) - interval + 1)}
hash_db = prepare2(my_huge_list_of_lists, interval=2)
def check_sublist2(hash_db, sublst): #use str() as hash function
hash_sub = str(sublst)
if hash_sub in hash_db:
return sublst == hash_db[hash_sub]
return False
print('By str():', timeit.timeit("check_sublist2(hash_db, test_lst)", setup="from __main__ import check_sublist2, my_huge_list_of_lists, test_lst, hash_db ", number=100))
#Solution 3: OP's current solution
def check_if_list_is_sublist(lst, sublst):
#checks if a list appears in order in another larger list.
n = len(sublst)
return any((sublst == lst[i:i + n]) for i in range(len(lst) - n + 1))
print('By OP\'s:', timeit.timeit("check_if_list_is_sublist(my_huge_list_of_lists, test_lst)", setup="from __main__ import check_if_list_is_sublist, my_huge_list_of_lists, test_lst ", number=100))
如果您想从一个列表中删除匹配的元素,这是可行的,但效果是您可能需要为新列表重建索引。除非列表是链表,否则请保存索引中每个元素的指针。我只是在googlePython上搜索如何获取列表中某个元素的指针,但找不到任何有用的东西。如果有人知道怎么做,请毫不犹豫地分享你的解决方案。谢谢
下面是一个示例:(它生成一个新列表而不是返回原始列表,有时我们仍然需要从原始列表中筛选一些内容)
对于一个大列表中的搜索匹配,我相信哈希(元素)然后构建索引将是一个很好的解决方案
您将获得的好处:
构建索引一次,节省时间供将来使用(无需为每次搜索重复循环)。
甚至,我们可以在启动程序时建立索引,然后在程序退出时释放它
下面的代码使用两种方法获取哈希值:hash()和str();有时,您应该根据特定场景自定义一个哈希函数
如果使用Stand(),代码看起来很简单,不需要考虑哈希冲突。但这可能会导致内存爆炸
对于hash(),我使用该列表保存所有具有相同hash值的sub_lst。您可以使用hash(sub_lst)%designed_length来控制hash大小(但它会增加hash冲突率)
以下代码的输出:
按散列:0.0002398660394852955
按str():0.00022884208565612796
按OP编号:0.3001317172469765
[以1.781s完成]
测试代码:
from random import randint
from string import ascii_lowercase
import timeit
#Generate Test Data
my_huge_list_of_lists = [[ascii_lowercase[randint(0, 25)] for x in range(50)] for y in range(10000)]
#print(my_huge_list_of_lists)
test_lst = [['a', 'b', 'c' ], ['a', 'b', 'c'] ]
#Solution 1: By using built-in hash function
def prepare1(huge_list, interval=1): #use built-in hash function
hash_db = {}
for index in range(len(huge_list) - interval + 1):
hash_sub = hash(str(huge_list[index:index+interval]))
if hash_sub in hash_db:
hash_db[hash_sub].append(huge_list[index:index+interval])
else:
hash_db[hash_sub] = [huge_list[index:index+interval]]
return hash_db
hash_db = prepare1(my_huge_list_of_lists, interval=2)
def check_sublist1(hash_db, sublst): #use built-in hash function
hash_sub = hash(str(sublst))
if hash_sub in hash_db:
return any([sublst == item for item in hash_db[hash_sub]])
return False
print('By Hash:', timeit.timeit("check_sublist1(hash_db, test_lst)", setup="from __main__ import check_sublist1, my_huge_list_of_lists, test_lst, hash_db ", number=100))
#Solution 2: By using str() as hash function
def prepare2(huge_list, interval=1): #use str() as hash function
return { str(huge_list[index:index+interval]):huge_list[index:index+interval] for index in range(len(huge_list) - interval + 1)}
hash_db = prepare2(my_huge_list_of_lists, interval=2)
def check_sublist2(hash_db, sublst): #use str() as hash function
hash_sub = str(sublst)
if hash_sub in hash_db:
return sublst == hash_db[hash_sub]
return False
print('By str():', timeit.timeit("check_sublist2(hash_db, test_lst)", setup="from __main__ import check_sublist2, my_huge_list_of_lists, test_lst, hash_db ", number=100))
#Solution 3: OP's current solution
def check_if_list_is_sublist(lst, sublst):
#checks if a list appears in order in another larger list.
n = len(sublst)
return any((sublst == lst[i:i + n]) for i in range(len(lst) - n + 1))
print('By OP\'s:', timeit.timeit("check_if_list_is_sublist(my_huge_list_of_lists, test_lst)", setup="from __main__ import check_if_list_is_sublist, my_huge_list_of_lists, test_lst ", number=100))
如果您想从一个列表中删除匹配的元素,这是可行的,但效果是您可能需要为新列表重建索引。除非列表是链表,否则请保存索引中每个元素的指针。我只是在googlePython上搜索如何获取列表中某个元素的指针,但找不到任何有用的东西。如果有人知道怎么做,请毫不犹豫地分享你的解决方案。谢谢
下面是一个示例:(它生成一个新列表而不是返回原始列表,有时我们仍然需要从原始列表中筛选一些内容)
虽然这本身并不是你所说的“答案”,但它是一个基准测试框架,可以帮助你确定最快的方法来完成你想要的,因为它允许相对容易的修改以及添加不同的方法
我把答案放在c