检查Python中的列表中是否有(不)

Check if something is (not) in a list in Python

我有一个python中的元组列表,并且我有一个条件,只有当元组不在列表中时,我才希望使用分支(如果它在列表中,那么我不希望使用if分支)

1
2
3
if curr_x -1 > 0 and (curr_x-1 , curr_y) not in myList:

    # Do Something

但这对我来说并不是真的有效。我做错了什么?


这个bug可能在代码中的其他地方,因为它可以正常工作:

1
2
3
4
>>> 3 not in [2, 3, 4]
False
>>> 3 not in [4, 5, 6]
True

或用元组:

1
2
3
4
>>> (2, 3) not in [(2, 3), (5, 6), (9, 1)]
False
>>> (2, 3) not in [(2, 7), (7, 3),"hi"]
True


How do I check if something is (not) in a list in Python?

最便宜和最易读的解决方案是使用in操作符(或者在您的特定情况下,使用not in操作符)。如文件所述,

The operators in and not in test for membership. x in s evaluates to
True if x is a member of s, and False otherwise. x not in s returns
the negation of x in s.

此外,

The operator not in is defined to have the inverse true value of in.

y not in x在逻辑上与not y in x相同。

以下是几个例子:

1
2
3
4
5
6
7
8
9
10
11
'a' in [1, 2, 3]
# False

'c' in ['a', 'b', 'c']
# True

'a' not in [1, 2, 3]
# True

'c' not in ['a', 'b', 'c']
# False

这也适用于元组,因为元组是可哈希的(因为它们也是不可变的):

1
2
(1, 2) in [(3, 4), (1, 2)]
#  True

如果rhs上的对象定义了__contains__()方法,那么in将在内部调用它,如文档比较部分的最后一段所述。

... in and not in,
are supported by types that are iterable or implement the
__contains__() method. For example, you could (but shouldn't) do this:

1
2
[3, 2, 1].__contains__(1)
# True

in短路,因此如果您的元素在列表的开头,in的计算速度更快:

1
2
3
4
5
6
lst = list(range(10001))
%timeit 1 in lst
%timeit 10000 in lst  # Expected to take longer time.

68.9 ns ± 0.613 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
178 μs ± 5.01 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

如果您想做的不仅仅是检查项目是否在列表中,还有以下选项:

  • list.index可用于检索项目的索引。如果该元素不存在,则会引发ValueError
  • 如果您想统计事件,可以使用list.count

xy问题:你考虑过sets吗?

问问自己这些问题:

  • 是否需要多次检查列表中的项目?
  • 这个检查是在一个循环中完成的,还是在一个反复调用的函数中完成的?
  • 您在列表中存储的项目是否可哈希?噢,你能打电话给他们吗?

如果您对这些问题的回答是"是",则应该使用setlistS上的in成员资格测试是O(n)时间复杂性。这意味着python必须对列表进行线性扫描,访问每个元素并将其与搜索项进行比较。如果重复执行此操作,或者列表很大,则此操作将产生开销。

另一方面,set对象散列它们的值以进行恒定时间成员身份检查。也可以使用in进行检查:

1
2
3
4
5
6
7
8
1 in {1, 2, 3}
# True

'a' not in {'a', 'b', 'c'}
# False

(1, 2) in {('a', 'c'), (1, 2)}
# True

如果不幸的是,您要搜索/不搜索的元素位于列表的末尾,那么python将一直扫描到列表的末尾。从以下时间点可以明显看出:

1
2
3
4
5
6
7
8
l = list(range(100001))
s = set(l)

%timeit 100000 in l
%timeit 100000 in s

2.58 ms ± 58.9 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
101 ns ± 9.53 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

作为提醒,只要存储和查找的元素是可哈希的,这是一个合适的选项。iow,它们要么是不可变的类型,要么是实现__hash__的对象。