【问题标题】:Use in operator in set of tuples python在元组 python 集中使用 in 运算符
【发布时间】:2017-04-18 10:08:15
【问题描述】:

我在尝试检查某个元素是否是 Python 中的集合的一部分时遇到了问题。 (我的集合包含大约 60 万个字符串元组。)

我正在寻找一种解决方案,该解决方案利用 in 运算符的优势来检查值是否是集合元组的元素。

我找到了类似的解决方案:

# S set of tuples, I'm checking if v is the second element of a tuple
any( y == v for (_, y) in S )

但这有 O(n) 复杂度。

Python 文档说 IN 运算符的平均复杂度为 O(1)。

编辑

我的问题是:如何使用in运算符的速度检查一个元素是否是集合中至少一个元组的第一个/第二个/...元素。

【问题讨论】:

  • 你的问题是?
  • 如何使用 IN 运算符的速度检查一个元素是否是集合中至少一个元组的第一个/第二个/...元素。
  • 是的,但是对每次搜索都执行此操作与我的代码具有相同的复杂性,因为创建新集合。

标签: python performance set tuples any


【解决方案1】:

包含测试的复杂性取决于对象类型,而不是操作员,因为操作是委托给容器的。测试列表中的包含是 O(n),集合中的包含是 O(1)。

但是,您不是在测试集合中的包容性,而是在一堆元组中测试包容性(元组的容器无法帮助)。没有进一步的处理,你不能比这里的 O(n) 做得更好。

您可以创建和维护单独的数据结构,例如,您可以跟踪元组中包含的单独值以及元组本身,然后针对这些单独的数据结构进行测试。这会增加内存需求,但会降低计算成本。

您将在程序的生命周期内摊销保持该结构最新的成本(只会稍微增加构建数据结构的恒定成本),作为回报,您可以在您的程序上获得 O(1) 次操作遏制测试。仅当您需要针对不同的值多次执行此测试时才执行此操作。

【讨论】:

  • "测试列表中的包含为 O(n),集合中的包含为 O(1)。"我今天确实学到了一些东西!
  • 我对降低计算成本很感兴趣,我没有内存问题。我的元组是一对像(键,值)这样的字符串。我也可以将它转换为一组简单的字符串(值),但我有必要知道这个值的原始键。
  • @LucaDiLiello:然后在构建元组时,跟踪单独集合或字典中的值(如果您需要这样的路径,后者也可以将值映射回键)。
  • @LucaDiLiello 听起来你需要dict
【解决方案2】:

IN 算子的平均复杂度为 O(1)

这对于集合中的成员资格检查或任何使用哈希表来存储其项目(如字典)的容器都是正确的。

这与关注in 完全不同:

for (_, y) in S

in 只是for 循环语法的一部分。

此外,如果您想获取包含特定字符串的元组,您可以使用列表推导而不是 any:

[item for item in S if my_str in item]

如果您想利用 set 的成员资格检查,您应该使用集合而不是元组,但由于它们不可散列,因此您不能在 set 中使用它们,在这种情况下您可以改用frozenset()

如果您只想检查是否存在满足特定条件的项目,您可以在 any 中使用以下生成器表达式:

any(my_str in item for item in S)

毕竟,由于您的集合完全有可能成为字典,您可以创建字典而不是集合,然后只需使用my_str in my_dict 检查成员资格。你的字典应该是这样的:{'luca': 1, 'mario': 2 , 'franco': 3}

【讨论】:

  • 是的,但我在 set([('luca',1),('mario',2),(' franco',3)])code
  • @LucaDiLiello 这就是我提到的。但是,如果您只想检查是否存在,any 会起作用,但表达式会稍有变化。查看更新。
  • 第一次创建后set中的值不会改变。我想我会使用字典。您的解决方案非常好,但对我的程序来说速度不够快,因为每次检查它都会扫描整个集合。
  • @LucaDiLiello 我正要提到这一点。您的 set 完全有可能成为字典,您可以创建字典而不是 set,然后只需使用 my_str in my_dict检查成员资格@
【解决方案3】:

按提出的方式回答问题(注意:这不是您通常想要解决的方式,因为它保证了O(n) 的行为,因为in 运算符不保证O(1),在这种情况下,永远不要确实)。

您可以使用in 运算符,将每个tuple 中的无关值映射出来。使用 C 级内置函数完成后,对于足够大的输入,这将比您的 any 表达式运行得更快,但差异很小(对于没有值的足够大的输入,可能会加快 10%):

 # At top of file
 from future_builtins import map  # Only on Py2, to get lazy map
 from operator import itemgetter

 v in map(itemgetter(1), S)

之所以有效,是因为 in 运算符是为任意迭代器实现的,作为类似于 any 的惰性检查,一次提取一个值,与 v 进行比较,如果找到命中则短路。

就像我说的,这是O(n);在现实世界中,如果您可能多次执行此测试,您可能只想制作目标的set 并重用它,或者如果需要,将目标映射到关联值的dict,以获取O(1) 支票。其他答案已经充分涵盖了这一点。

【讨论】:

  • 谢谢,但我使用的是字典,因为我需要花很多时间进行检查。我在一个非常大的数据集上的 Spark 的 Map 函数中使用它。
猜你喜欢
  • 1970-01-01
  • 2022-11-23
  • 2012-09-27
  • 2012-07-11
  • 2016-09-09
  • 2018-04-15
  • 2012-04-29
  • 2018-06-14
相关资源
最近更新 更多