检查Python列表中是否有东西


314

我在Python中有一个元组列表,并且有一个条件,如果元组不在列表中,那么我只想接受分支(如果它在列表中,那么我就不想接受if分支)

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

    # Do Something

不过,这对我来说并不是很有效。我做错了什么?


1
注意3 -1 > 0 and (4-1 , 5) not in []True因此错误不是运算符优先级之一。
Dan D.

6
“不是真的为我工作”是什么意思?您期望发生什么?实际发生了什么?哪些确切的列表内容会触发问题?
Karl Knechtel

为什么不试试myList.count((curr_x, curr_y)),如果(curr_x, curr_y)在不是myList,其结果将是0
LittleLittleQ


2
这个“我的代码对我不是很有效”的问题如何获得297票赞成?请给我们一个最小的可复制示例
Gerrit

Answers:


502

该错误可能在代码中的其他地方,因为它应该可以正常工作:

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

或与元组:

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

11
@Zack:如果您不知道这件事,您可以做if not ELEMENT in COLLECTION:
ninjagecko 2012年

@ninjagecko:取决于效率可能较低甚至不正确的容器类型。参见例如bloom过滤器
orlp 2012年

14
@nightcracker没有意义,因为A not in B减少到做not B.__contains__(A)什么not A in B与减少到是一样not B.__contains__(A)
Dan D.

1
哇,我可以宣誓Python有类似的东西__notcontains__。对不起,那我所说的只是胡说。
orlp 2012年

2
@ std''OrgnlDave唯一可能发生的方法是,如果not优先级高于in不存在的优先级。考虑将结果归结为A的ast.dump(ast.parse("not A in B").body[0])结果,"Expr(value=UnaryOp(op=Not(), operand=Compare(left=Name(id='A', ctx=Load()), ops=[In()], comparators=[Name(id='B', ctx=Load())])))"如果not将其紧紧地归为A,则可以预期结果"Expr(value=Compare(left=UnaryOp(op=Not(), operand=Name(id='A', ctx=Load())), ops=[In()], comparators=[Name(id='B', ctx=Load())]))"是的解析"(not A) in B"
Dan D.

20

如何检查Python列表中是否包含某些内容?

最便宜,最易读的解决方案是使用in运算符(或在您的特定情况下为not in)。如文档中所述,

运营商innot in进行会员资格测试。x in s评估 True是否x为的成员sFalse否则为。x not in s返回的否定x in s

另外,

运算符not in被定义为具有的反真值in

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

这里有一些例子:

'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) in [(3, 4), (1, 2)]
#  True

如果RHS上的对象定义了一个__contains__()方法,in则将在内部调用该方法,如文档“ 比较”部分的最后一段所述。

... innot in,由可迭代或实现该__contains__()方法的类型支持 。例如,您可以(但不应)这样做:

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

in短路,因此,如果您的元素位于列表的开头,则in求值速度更快:

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则引发a。
  • list.count 如果您要计算发生次数,可以使用。

XY问题:您考虑过sets吗?

问自己以下问题:

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

如果您对这些问题的回答为“是”,则应改用“ a” set。s 的in隶属度检验list是O(n)时间复杂度。这意味着python必须对列表进行线性扫描,访问每个元素并将其与搜索项进行比较。如果您重复执行此操作,或者列表很大,那么此操作将产生开销。

set另一方面,对象会对其值进行哈希处理以进行恒定时间成员资格检查。该检查也可以使用in

1 in {1, 2, 3} 
# True

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

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

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

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__


2
集并不总是一个选项(例如,当具有可变项列表时)。对于大型集合:无论如何,为查询建立集合的时间为O(n),并且可能使内存使用量增加一倍。如果您还没有进行查找,那么它并不是制作/维护一个的最佳选择。
维姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.