以大名单开头的获取第一价值的最有效方法

问题描述

我有一个非常大的列表,其中包含超过1亿个字符串。该列表的示例如下:

l = ['1,1,5.8067','1,2,4.9700','2,3.9623',3,1.9438',7,1.0645','3,8.9331',5,2.6772',3.8107',9,7.1008']

我想获取一个以例如'3'。

为此,我使用了lambda迭代器,然后使用next()来获取第一项:

next(filter(lambda i: i.startswith('3,'),l))
Out[1]: '3,8.9331'

考虑到列表的大小,不幸的是,对于我不得不一遍又一遍地执行的过程而言,此策略仍需要花费大量时间。我想知道是否有人可以提出一种更快,更有效的方法。我愿意接受其他策略。

解决方法

由于在按制表符分割字符串之后,由于实际的字符串由较短的标记(例如301)组成,因此您可以使用第一个标记的每个可能长度作为键来构建字典,以便后续查找平均时间复杂度只有 O(1)

以相反的顺序用列表值构建字典,以便列表中以每个不同字符开头的第一个值将保留在最终字典中:

d = {s[:i + 1]: s for s in reversed(l) for i in range(len(s.split('\t')[0]))}

所以给定:

l = ['301\t301\t51.806763\n','301\t302\t46.970094\n','301\t303\t39.962393\n','301\t304\t18.943836\n','301\t305\t11.064584\n','301\t306\t4.751911\n']

d['3']将返回'301\t301\t51.806763'

如果您只需要整体测试每个第一个标记而不是前缀,则可以简单地将第一个标记作为键:

d = {s.split('\t')[0]: s for s in reversed(l)}

以便d['301']将返回'301\t301\t51.806763'

,

我无法自己对其进行测试,但是有可能如果您将所有字符串与一个不在任何字符串中的char连接起来:

concat_list = '$'.join(l)

现在使用简单的.find('$3,'),它将更快。如果所有字符串都较短,则可能会发生这种情况。从现在开始,所有字符串都在内存中的一个位置。


如果文本中唯一字母的数量很少,则可以使用Abrahamson-Kosaraju方法,而时间复杂度实际上为O(n)


另一种方法是使用joblib,当第n个线程正在检查i时创建i + k * n个线程,当一个发现模式停止其他线程时。因此,时间复杂度为O(naive algorithm / n)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...