在列表

时间:2016-03-01 09:49:40

标签: python list tuples

说我有元组列表:

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

Python中有没有办法编写像

这样的东西
if (1, *) in list: do things

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

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

P.S。:我知道我可以在这里使用列表推导。我只是对这种特殊机制感兴趣。

7 个答案:

答案 0 :(得分:71)

您可以使用any() function

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

如果在元组的第一个位置找到1,这会有效地测试并退出。

答案 1 :(得分:33)

像您一样要求的占位符对象本身不受支持,但您可以自己制作类似的内容:

class Any(object):
    def __eq__(self, other):
        return True
ANYTHING = Any()

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

__eq__方法定义了两个对象如何测试相等性。 (有关详细信息,请参阅https://docs.python.org/3/reference/datamodel.html。)在此,ANYTHING将始终测试与任何对象相等的正数。 (除非该对象也以一种返回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__如果其所有元素' __eq__都返回True,则返回True。即(x, y) == (a, b)相当于x==a and y==bx.__eq__(a) and y.__eq__(b) }。)

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

另请注意,我重命名了您的列表lst而不是list,以防止与内置的list进行名称冲突。

答案 2 :(得分:10)

并非下面提供的所有解决方案方法都必须有效。我的目标是展示我能想到的每种可能的解决方案 - 在我的回答结束时我提供"基准"结果显示为什么或为什么不使用某种方法而不是另一种方法。我相信这是一种很好的学习方式,我会在答案中无耻地鼓励这样的学习。

子集+哈希set s

>>> 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

微基准

条件

  • 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(至少我试过)

故事的道德:不要花费超过10分钟"证明"当另一个用户的答案是事实上正确的答案

时,你的劣质解决方案对于小型测试数据更快更有效

答案 3 :(得分:5)

这可以使用list comprehension在Python中完成。 例如:

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

会给你:

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

答案 4 :(得分:3)

索引是最简单的,但是如果你想使用类似于你的例子的语法,你想把第一个值分配给一个变量而忽略其余的你可以使用python3' s extended iterable unpacking

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]

答案 5 :(得分:2)

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

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

答案 6 :(得分:0)

听起来你真的想要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()方法非常棒,因为您可以直接向它提供函数。这允许您指定要过滤的某个键,等等。为了进一步简化它,使用lambda表达式将整个事物变成一个单行。