在列表中查找包含未知值的元组结构

假设我有元组列表:

list = [(1,5), (1,7), (2,3)] 

有没有办法用Python来写类似的东西

 if (1, *) in list: do things 

其中*表示“ 我不关心这个值 ”? 所以我们正在检查在第一个位置是否有一个元组,而第二个元组是否有值。

据我所知,在其他语言中有特殊的机制,但我不知道这个特定问题的名称。 那么在Python中是否有类似的行为?

PS:我知道我可以在这里使用列表parsing。 我只是对这个特定的机制感兴趣。

像你所要求的占位符对象本身不支持,但你可以自己做这样的事情:

 class Any(object): def __eq__(self, other): return True ANYTHING = Any() lst = [(1,5), (1,7), (2,3)] 

__eq__方法定义了两个对象如何testing相等性。 (有关详细信息,请参阅https://docs.python.org/3/reference/datamodel.html 。)在这里, ANYTHING将始终testing与任何对象相等的正数。 (除非这个对象也以一种返回False的方式覆盖__eq__ )。

in运算符仅仅为列表中的每个元素调用__eq__ 。 即a in b做类似的事情:

 for elem in b: if elem == a: return True 

这意味着,如果你在(1, ANYTHING) in lst说,Python将首先比较(1, ANYTHING)lst的第一个元素。 (元组依次定义__eq__返回True,如果它的所有元素__eq__返回True。Ie (x, y) == (a, b)相当于x==a and y==b或者x.__eq__(a) and y.__eq__(b) 。)

因此, (1, ANYTHING) in lst将返回True,而(1, ANYTHING) in lst (3, ANYTHING) in lst将返回False。

另外请注意,我将列表重命名为lst而不是list以防止名称与Python内置list冲突。

你可以使用any()函数 :

 if any(t[0] == 1 for t in yourlist): 

如果在元组的第一个位置find1这将有效地testing并退出。

下面提供的解决方法并非都是有效的。 我的目标是展示我能想到的所有可能的解决scheme – 在我的答案结尾处,我提供了“基准”结果来说明为什么或者为什么不应该使用某种方法而不是另一种方法。 我相信这是一种很好的学习方式,我会在我的答案中无耻的鼓励这种学习。


子集+哈希set

 >>> a_list = [(1,5), (1,7), (2,3)] >>> >>> set([l[0] for l in a_list]) {1, 2} >>> >>> 1 in set([l[0] for l in a_list]) True 

map()和匿名函数

 >>> a_list = [(1,5), (1,7), (2,3)] >>> >>> map(lambda x: x[0] == 1, a_list) [True, True, False] >>> >>> True in set(map(lambda x: x[0] == 1, a_list)) True 

filter和匿名函数

 >>> a_list = [(1,5), (1,7), (2,3)] >>> >>> filter(lambda x: x[0] == 1, a_list) [(1,5), (1,7)] >>> >>> len(filter(lambda x: x[0] == 1, a_list)) > 0 # non-empty list True 

微基准testing

条件

  • 1000个项目
  • 100K的重复
  • 0-100随机范围
  • Python 2.7.10,IPython 2.3.0

脚本

 from pprint import pprint from random import randint from timeit import timeit N_ITEMS = 1000 N_SIM = 1 * (10 ** 5) # 100K = 100000 a_list = [(randint(0, 100), randint(0, 100)) for _ in range(N_ITEMS)] set_membership_list_comprehension_time = timeit( "1 in set([l[0] for l in a_list])", number = N_SIM, setup="from __main__ import a_list" ) bool_membership_map_time = timeit( "True in set(map(lambda x: x[0] == 1, a_list))", number = N_SIM, setup="from __main__ import a_list" ) nonzero_length_filter_time = timeit( "len(filter(lambda x: x[0] == 1, a_list)) > 0", number = N_SIM, setup="from __main__ import a_list" ) any_list_comprehension_time = timeit( "any(t[0] == 1 for t in a_list)", number = N_SIM, setup="from __main__ import a_list" ) results = { "any(t[0] == 1 for t in a_list)": any_list_comprehension_time, "len(filter(lambda x: x[0] == 1, a_list)) > 0": nonzero_length_filter_time, "True in set(map(lambda x: x[0] == 1, a_list))": bool_membership_map_time, "1 in set([l[0] for l in a_list])": set_membership_list_comprehension_time } pprint( sorted(results.items(), key = lambda x: x[1]) ) 

结果(以秒为单位)

 [('any(t[0] == 1 for t in a_list)', 2.6685791015625), # winner - Martijn ('1 in set([l[0] for l in a_list])', 4.85234808921814), ('len(filter(lambda x: x[0] == 1, a_list)) > 0', 7.11224889755249), ('True in set(map(lambda x: x[0] == 1, a_list))', 10.343087911605835)] 

谁现在笑到最后了? Martijn(至less我试过了)

故事的道理:不要花费超过10分钟“certificate”你的劣质解决scheme在小的testing数据上更快,更高效,而另一个用户的答案实际上是正确的

这可以使用列表理解在Python中完成。 例如:

 a= [(1, 2), (3, 4), (4, 5), (1, 4)] [i for i in a if i[0] == 1] 

会给你:

 [(1, 2), (1, 4)] 

索引是最简单的,但如果您想使用类似于您想要将第一个值赋予variables的示例的语法,并忽略其余部分,则可以使用python3的扩展迭代解包 。

 In [3]: [a for a,*_ in l] Out[3]: [1, 1, 2] 

或者用任何逻辑:

 In [4]: l = [(1,5), (1,7), (2,3)] In [5]: any(a == 1 for a,*_ in l) Out[5]: True 

或模仿任何没有函数调用:

 In [23]: l = [(1,5), (1,7), (2,3)] In [24]: g = (a for a,*_ in l) In [25]: 1 in g Out[25]: True In [26]: list(g) Out[26]: [1, 2] 

元组中元素的个数也可以被处理。

 >>> import operator >>> mylist = [(1,2), (1,5), (4,5,8)] >>> any(i==1 for i in map(operator.itemgetter(0), mylist)) True 

这听起来像你实际上想filter() ,而不是any()

 tuple_list = [(1,5), (1,7), (2,3)] for pair in filter(lambda pair: (pair[0] == 1), tuple_list): print "Second value {pair[1]} found from {pair}".format(pair=pair) ... Second value 5 found from (1, 5) Second value 7 found from (1, 7) 

filter()方法很好,因为你可以直接给它提供一个函数。 这可以让你指定一个特定的键过滤,等等。为了进一步简化,使用一个lambdaexpression式来使整个事情变成一个单行。