当前位置: 首页 > news >正文

01_Python的in运算符判断列表等是否包含特定元素

Python的in运算符判断列表等是否包含特定元素

使用Python的运算符in和not in,可以确认和判断列表、元组等是否包含(存在)特定元素。

目录

  • in运算符的用法

    • 基本用法
    • 根据值是否相等进行判断
    • 在if语句中的条件分支
    • 针对字典dict的in
    • 针对字符串str的in
    • 使用not in(否定)确认不存在
    • 针对多个元素的in
      • 使用and, or
      • 使用集合
    • in的处理速度比较
      • 列表list较慢: O(n)
      • 集合set较快: O(1)
      • 对于字典dict
  • 在for语句和列表推导式中的in

in运算符的用法

基本用法

可以像以下这样以x in y的形式书写。如果x包含在y中则返回True,不包含则返回False。

print(1 in [0, 1, 2])
# True
print(100 in [0, 1, 2])
# False

除了列表,还可以对元组、集合set、range等可迭代对象进行运算。

print(1 in (0, 1, 2))
# True
print(1 in {0, 1, 2})
# True
print(1 in range(3))
# True

字典dict、字符串str的情况将在后文中说明。

根据值是否相等进行判断

通过in进行的判断与==相同,根据值是否相等进行判断。即使类型不同但值相等,也会返回True。

print(1.0 == 1)
# True
print(1.0 in [0, 1, 2])
# True
print(True == 1)
# True
print(True in [0, 1, 2])
# True

此外,由于bool是整数int的子类,True, False分别等价于1, 0。

在if语句中的条件分支

通过in进行的运算返回布尔值(True, False),可以直接用作if语句的条件式。

l = [0, 1, 2]
i = 0
if i in l:print(f'{i} is a member of {l}.')
else:print(f'{i} is not a member of {l}.')
# 0 is a member of [0, 1, 2].
l = [0, 1, 2]
i = 100
if i in l:print(f'{i} is a member of {l}.')
else:print(f'{i} is not a member of {l}.')
# 100 is not a member of [0, 1, 2].

此外,列表、元组、字符串等如果为空则为False,不为空则为True。如果想根据是否为空进行条件分支,可以直接使用对象作为条件式。

l = [0, 1, 2]
if l:print(f'{l} is not empty.')
else:print(f'{l} is empty.')
# [0, 1, 2] is not empty.
l = []
if l:print(f'{l} is not empty.')
else:print(f'{l} is empty.')
# [] is empty.

针对字典dict的in

直接在字典dict上使用in运算,将进行键的判断。

d = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
print('key1' in d)
# True
print('value1' in d)
# False

如果要处理值或键值对的组合,请使用values()和items()。

print('value1' in d.values())
# True
print(('key1', 'value1') in d.items())
# True
print(('key1', 'value2') in d.items())
# False

针对字符串str的in

对于字符串str,可以进行子字符串的判断。

print('a' in 'abc')
# True
print('x' in 'abc')
# False
print('ab' in 'abc')
# True
print('ac' in 'abc')
# False

使用not in(否定)确认不存在

in运算符的否定使用not in。

print(10 in [1, 2, 3])
# False
print(10 not in [1, 2, 3])
# True

对整个in运算加not也能得到相同结果。

print(not 10 in [1, 2, 3])
# True

不过,对整个in运算加not时,由于可以有两种解释(not作用的范围不同),建议使用更明确的not in。

print(not (10 in [1, 2, 3]))
# True
print((not 10) in [1, 2, 3])
# False

因为in比not优先级高(先被处理),所以没有括号时按前者处理。

顺便说一下,后者的情况如下。

print(not 10)
# False
print(False in [1, 2, 3])
# False

针对多个元素的in

如果想判断是否包含多个元素,像下面这样用列表写多个元素是行不通的。这会变成判断列表本身是否包含。

print([0, 1] in [0, 1, 2])
# False
print([0, 1] in [[0, 1], [1, 0]])
# True

可以使用and, or,或者使用集合set。

使用and, or

使用逻辑运算符and(并且)、or(或者)组合多个in运算。可以判断是否都包含,或者至少包含一个。

l = [0, 1, 2]
v1 = 0
v2 = 100
print(v1 in l and v2 in l)
# False
print(v1 in l or v2 in l)
# True
print((v1 in l) or (v2 in l))
# True

in, not in比and, or优先级高(先被处理),所以括号不是必须的,但如果觉得不清晰,可以像最后一个例子那样加括号。

使用集合

如果想判断的元素数量多,使用集合set比and, or简单。

例如,判断列表A是否包含列表B的所有元素,可以判断列表B是否是列表A的子集(或者列表A是否是列表B的超集)。

l1 = [0, 1, 2, 3, 4]
l2 = [0, 1, 2]
l3 = [0, 1, 5]
l4 = [5, 6, 7]
print(set(l2) <= set(l1))
# True
print(set(l3) <= set(l1))
# False

如果想判断列表A是否没有包含列表B的任何元素,可以确认列表A和列表B是否互不相交。

print(set(l1).isdisjoint(set(l4)))
# True

如果列表A和列表B不互不相交,可以判断列表A至少包含列表B的一个元素。

print(not set(l1).isdisjoint(set(l3)))
# True

in的处理速度比较

in运算符的处理速度因对象类型而异。

这里显示对列表、集合、字典的in处理速度的测量结果。以下代码使用了Jupyter Notebook的魔法命令%%timeit,作为Python脚本执行时无法测量,请注意。

以元素数为10和10000的列表为例。

n_small = 10
n_large = 10000
l_small = list(range(n_small))
l_large = list(range(n_large))

以下是使用CPython3.7.4的结果,在其他实现中可能不同。如果没有使用特殊实现,可以认为是CPython。此外,当然,测量结果的绝对值因环境而异。

列表list较慢: O(n)

对列表list的in运算符的平均时间复杂度是O(n)。元素数量多时会变慢。注意结果的单位。

%%timeit
-1 in l_small
# 178 ns ± 4.78 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
-1 in l_large
# 128 µs ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

处理时间根据查找值的位置变化很大。查找值在最后或不存在时耗时最长。

%%timeit
0 in l_large
# 33.4 ns ± 0.397 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
5000 in l_large
# 66.1 µs ± 4.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
9999 in l_large
# 127 µs ± 2.17 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

集合set较快: O(1)

对集合set的in运算符的平均时间复杂度是O(1)。不依赖于元素数量。

s_small = set(l_small)
s_large = set(l_large)
%%timeit
-1 in s_small
# 40.4 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
-1 in s_large
# 39.4 ns ± 1.1 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

不像列表,查找值不会大幅改变处理时间。

%%timeit
0 in s_large
# 39.7 ns ± 1.27 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
5000 in s_large
# 53.1 ns ± 0.974 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
9999 in s_large
# 52.4 ns ± 0.403 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

对于元素多的列表,重复使用in进行处理的情况,预先转换为集合set速度较快。注意结果的单位。

%%timeit
for i in range(n_large):i in l_large
# 643 ms ± 29.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
s_large_ = set(l_large)
for i in range(n_large):i in s_large_
# 746 µs ± 6.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

需要注意的是,从列表转换为set也需要耗时,in处理次数少时保持为列表可能更快。

对于字典dict

以键和值相同的字典为例。

d = dict(zip(l_large, l_large))
print(len(d))
# 10000
print(d[0])
# 0
print(d[9999])
# 9999

如上所述,直接在字典dict上使用in运算将进行键的判断。字典的键与集合set一样是唯一值,与set的处理速度相近。

%%timeit
for i in range(n_large):i in d
# 756 µs ± 24.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

另一方面,字典的值允许重复。针对values()的in处理速度与列表同等。

dv = d.values()
%%timeit
for i in range(n_large):i in dv
# 990 ms ± 28.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

键值对是唯一的。针对items()的in处理速度约为set + α。

di = d.items()
%%timeit
for i in range(n_large):(i, i) in di
# 1.18 ms ± 26.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在for语句和列表推导式中的in

在for语句和列表推导式的语法中也使用了in一词。此处的in不是in运算符,也不返回True或False。

l = [0, 1, 2]
for i in l:print(i)
# 0
# 1
# 2
print([i * 10 for i in l])
# [0, 10, 20]

在列表推导式中作为条件式使用in运算符的情况也有,需注意。

l = ['oneXXXaaa', 'twoXXXbbb', 'three999aaa', '000111222']
l_in = [s for s in l if 'XXX' in s]
print(l_in)
# ['oneXXXaaa', 'twoXXXbbb']

开头的in是列表推导式中的in,后面的in是in运算符。

http://www.xdnf.cn/news/1350001.html

相关文章:

  • C语言初学者笔记【动态内存管理】
  • 深入探讨集成学习:Bagging与Boosting的核心原理与实践
  • 自然语言处理——05 Transformer架构和手写实现
  • 复杂街景误检率↓79%!陌讯动态融合算法在街道垃圾识别的边缘计算优化​​
  • Mysql之binlog日志说明及利用binlog日志恢复数据操作记录
  • 链表漫游指南:C++ 指针操作的艺术与实践
  • 蓝牙链路层状态机精解:从待机到连接的状态跃迁与功耗控制
  • 【大语言模型 15】因果掩码与注意力掩码实现:深度学习中的信息流控制艺术
  • Python本源诗话(我DeepSeek)
  • 企业视频库管理高效策略
  • 大数据接口 - 企业风险报告(专业版)API接口文档
  • 使用springboot开发-AI智能体平台管理系统,统一管理各个平台的智能体并让智能体和AI语音设备通信,做一个属于自己的小艾同学~
  • 百度深度学习面试:batch_size的选择问题
  • 36_基于深度学习的智能零售柜物品检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
  • 【深度学习新浪潮】有哪些工具可以帮助我们对视频进行内容分析和关键信息提取?
  • LeetCode56合并区间
  • Idea中 lombok 在“测试类中-单元测试”运行失败及解决方法
  • 商超高峰客流统计误差↓75%!陌讯多模态融合算法在智慧零售的实战解析
  • Elasticsearch:什么是神经网络?
  • Elasticsearch Persistence(elasticsearch-persistence)仓储模式实战
  • 批量归一化:不将参数上传到中心服务器,那服务器怎么进行聚合?
  • 浏览器解析网址的过程
  • 倍福下的EC-A10020-P2-24电机调试说明
  • 【JVM】JVM的内存结构是怎样的?
  • mysql为什么使用b+树不使用红黑树
  • Elasticsearch Ruby 客户端 Bulk Scroll Helpers 实战指南
  • TopK问题(堆排序)-- go
  • MySQL存储过程入门
  • 中农具身导航赋能智慧农业!AgriVLN:农业机器人的视觉语言导航
  • PostgreSQL15——查询详解