Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在字符串列表中搜索其他列表中的任何子字符串_Python - Fatal编程技术网

Python 在字符串列表中搜索其他列表中的任何子字符串

Python 在字符串列表中搜索其他列表中的任何子字符串,python,Python,给出这3个数据列表和一个关键字列表: good_data1 = ['hello, world', 'hey, world'] good_data2 = ['hey, man', 'whats up'] bad_data = ['hi, earth', 'sup, planet'] keywords = ['world', 'he'] 我试图编写一个简单的函数来检查是否有任何关键字作为数据列表中任何单词的子字符串存在。对于good\u数据列表,它应该返回True;对于bad\u数据,它应该返回F

给出这3个数据列表和一个关键字列表:

good_data1 = ['hello, world', 'hey, world']
good_data2 = ['hey, man', 'whats up']
bad_data = ['hi, earth', 'sup, planet']
keywords = ['world', 'he']
我试图编写一个简单的函数来检查是否有任何关键字作为数据列表中任何单词的子字符串存在。对于
good\u数据
列表,它应该返回True;对于
bad\u数据
,它应该返回False

我知道如何以一种似乎效率低下的方式进行:

def checkData(data):
  for s in data:
    for k in keywords:
      if k in s:
        return True
  return False
你在找什么

any( k in s for k in keywords )

它更紧凑,但效率可能更低。

我认为这是非常有效和清晰的,尽管您可以使用map()来避免许多嵌套。我同意ross关于更大列表的字典想法。

您可以通过将关键字列表构建为正则表达式来改进问题

这可能允许对它们进行并行测试,但在很大程度上取决于关键字是什么(例如,一些工作可能会重复使用,测试“hello”和“hell”,而不是从一开始就搜索每个单词的每个短语)

您可以通过执行以下命令来完成此操作:

import re
keyword_re = re.compile("|".join(map(re.escape, keywords)))
然后:

(它实际上会在找到时返回一个匹配对象,如果找不到,则不会返回任何对象-如果您需要知道哪个关键字匹配,这可能会很有用)

但是,这会给您带来多少好处(如果有的话)取决于关键字。如果您只有一两个关键字,请保留当前的方法。如果您有一个大的列表,则可能值得尝试和分析,以查看哪一个性能更好

[编辑] 以下是这些方法如何为您的示例提供参考:

               good1   good2  good3   bad1   bad2
original     : 0.206   0.233  0.229   0.390   63.879
gnud (join)  : 0.257   0.347  4.600   0.281    6.706
regex        : 0.766   1.018  0.397   0.764  124.351
regex (join) : 0.345   0.337  3.305   0.481   48.666
显然,在这种情况下,您的方法的性能要比正则表达式好得多。是否始终如此,在很大程度上取决于关键字的数量和复杂性,以及要检查的输入数据。对于大量关键字、冗长的列表或很少匹配的短语,正则表达式可能工作得更好,但确实可以获得时间信息,或许可以先尝试更简单的优化(比如将最常见的单词移到关键词列表的前面)。有时候最简单的方法确实是最好的

[Edit2]在应用正则表达式之前,使用和类似的方法更新了表。我还添加了两个新测试:

good_data3 = good_data2 * 500  # 1000 items, the first of which matches.
bad_data2 = bad_data * 500     # 1000 items, none of which matches.

这显示了各种优势和劣势。当一个匹配项立即被发现时,加入会变得更糟(因为加入列表总是要付出前期成本——这是线性搜索方法的最佳情况),但是对于不匹配的列表,它的性能更好。当列表中有大量项目时,它的性能会更好。在您的示例中,项目太少,这并不重要。但是如果你有一个包含数千项的列表,这可能会有所帮助

由于您不关心列表中的哪个元素包含关键字,因此可以一次扫描整个列表(作为一个字符串),而不是一次扫描一个项目。为此,您需要一个已知不会出现在关键字中的连接字符,以避免误报。我在这个例子中使用了换行符

def check_data(data):
    s = "\n".join(data);
    for k in keywords:
        if k in s:
            return True

    return False

在我完全不科学的测试中,我的版本在大约30秒内检查了5000个项目的列表100000次。我在3分钟后停止了你的版本--厌倦了等待post=)

如果你有很多关键词,你可能想试试后缀树[1]。插入三个数据列表中的所有单词,将每个单词来自哪个列表存储在其终止节点中。然后,您可以非常非常快速地对每个关键字在树上执行查询

警告:后缀树的实现非常复杂


[1]

虽然它更紧凑,但可读性要差得多。非常完美的IMHO.+1这对于小的关键字列表来说是非常简洁的-1:它很紧凑,但实际上并没有回答问题(他要求的是子字符串匹配,而不是精确匹配)。不过这是可行的:any(k in s代表s in data代表k in关键字)@mhawke:我相信目的是将代码放在“for s in data”循环中-注意,他正在搜索的变量在内部循环中命名为“s”,而不是列表中的“data”。放在那里,这是一个子字符串搜索。使用外循环的IMHO比双循环的理解更具可读性。谢谢S.洛特!我将这个答案与gnud的组合使用:“s”是连接的字符串。我接受gnud的答案,因为他想加入阵营,而且级别要低得多。很好的解决方案,我正是这么想的。与正则表达式相比,它应该非常快,因为包含检查是用修改的Boyer Moore完成的,因此应该跳过分隔符。好主意,它确实对大型列表有着非常重要的影响——可能正如托尔斯滕所说的,因为python可以重用它创建的搜索表,而不是将它们扔掉并为每个列表项重新创建它们。我会更新我的计时数据。加入阵列是个好主意!我决定将其与S.Lott对any()函数的建议结合使用。谢谢这真是太棒了,非常聪明,干得不错,兄弟。不过请注意,正则表达式在有限状态机上也能有效地执行同样的操作。我怀疑它也会执行类似的操作,除了由于在python和C中编写代码而以常数因子的速度变慢之外。大多数正则表达式库都不是使用fsm实现的。任何允许反向引用的正则表达式库都是如此。否则你就完全正确了。尽管如此,这一点还是很好的。说得好,看来我还是错了。我只是看了一下re.compile(“abc | abd | abb | acb”,re.DEBUG),很少有分支的共享,这表明它很可能会回溯到每个单词的开头。感谢您的解释。
def check_data(data):
    s = "\n".join(data);
    for k in keywords:
        if k in s:
            return True

    return False