百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Python标准库及第三方库4-itertools模块

bigegpt 2024-08-31 16:45 2 浏览

前言

这次分享的主题是Python内置的itertools模块,它能够帮助开发人员更快速地实现迭代器。

在之前的章节中,我们介绍过Python可迭代对象、迭代器以及二者的区别联系,先来简单回顾一下:

1.可迭代对象、迭代器的基础概念

迭代:通过for循环遍历取值的过程叫做迭代;

可迭代对象:能够通过for循环遍历取值的对象都是可迭代对象,如:字符串、列表、元组、字典、集合、range;

迭代器:既可以通过for循环遍历取值,也可以通过next()函数取值的对象就是迭代器对象;

2.可迭代对象、迭代器的区别与联系

  • 迭代器和可迭代对象都可以用作for循环遍历;
  • 迭代器一定是可迭代对象,因为同时实现了__iter__方法和__next__方法,可以通过next()方法获取下一个值,但是每个值只能获取一次;
  • 但可迭代对象并不一定是迭代器,例如列表、字典、字符串,它们只实现了__iter__方法,如果想变成迭代器对象可以使用iter()进行转换;
  • 只要可以用for循环遍历的都是可迭代对象,只要可以用next()函数遍历的都是迭代器对象;
  • 可迭代对象是一次性将所有元素都加载到内存中,当可迭代对象长度较长时,会占用大量系统资源;而迭代器则是每次只获取一个、返回一个元素,不会造成资源浪费,在性能上优于可迭代对象;

itertools-为高效循环而创建迭代器的函数

itertools 模块标准化了一个快速、高效利用内存的核心工具集,这些工具本身或组合都很有用。它们一起形成了“迭代器代数”,这使得在纯Python中有可能创建简洁又高效的专用工具。

1.无穷迭代器

迭代器

实参

结果

示例

count()

start, [step]

start, start+step, start+2*step, ...

count(10) --> 10 11 12 13 14 ...

cycle()

p

p0, p1, ... plast, p0, p1, ...

cycle('ABCD') --> A B C D A B C D ...

repeat()

elem [,n]

elem, elem, elem, ... 重复无限次或n次

repeat(10, 3) --> 10 10 10

count()方法

使用count 打印1-100的所有奇数,最终结果会循环到101即停止:

import itertools

"""无穷迭代器"""
# count 打印1-100的所有奇数
it = itertools.count(start=1, step=2)
for i in it:
    print(i)
    if i > 100:
        break

cycle()方法-指定迭代对象中元素的循环次数

使用cycle 对列表中的元素指定循环次数,因为列表有5个元素,所以for循环会在count为11时停止,此时列表循环2遍、循环到第3遍,也就是第一个元素1的时候停止。

# cycle 对列表中的元素指定循环次数
testlist = [1, 2, 3, 4, 5]
ic = itertools.cycle(testlist)
count = 0
for i in ic:
    print(i)
    count += 1
    if count == 11:
        break

'''
1
2
3
4
5
1
2
3
4
5
1
'''

repeat()方法-指定可迭代对象的重复次数

使用repeat, 指定列表的迭代次数,重复无限次或n次:

# repeat 指定列表的迭代次数
testlist = [1, 2, 3, 4, 5]
ir = itertools.repeat(object=testlist, times=3)
for i in ir:
    print(i)

'''
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
'''

2.排列组合迭代器

迭代器

实参

结果

product()

p, q, ... [repeat=1]

笛卡尔积,相当于嵌套的for循环

permutations()

p[, r]

长度r元组,所有可能的排列,无重复元素

combinations()

p, r

长度r元组,有序,无重复元素

combinations_with_replacement()

p, r

长度r元组,有序,元素可重复

product('ABCD', repeat=2)


AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD

permutations('ABCD', 2)


AB AC AD BA BC BD CA CB CD DA DB DC

combinations('ABCD', 2)


AB AC AD BC BD CD

combinations_with_replacement('ABCD', 2)


AA AB AC AD BB BC BD CC CD DD

itertools.product()-获取迭代对象的笛卡尔积

列表testlist中有5个元素,元组dev_lan中有5个元素,所以它们的笛卡尔积一共会有25个结果:

# product 获取迭代对象的笛卡尔积
testlist = [1, 2, 3, 4, 5]
dev_lan = ("python", "java", "c++", "go", "ruby")
ip = itertools.product(testlist, dev_lan)
count = 0
for p in ip:
    print(p)
    count += 1
print(count)
'''
(1, 'python')
(1, 'java')
(1, 'c++')
(1, 'go')
(1, 'ruby')
(2, 'python')
(2, 'java')
(2, 'c++')
(2, 'go')
(2, 'ruby')
(3, 'python')
(3, 'java')
(3, 'c++')
(3, 'go')
(3, 'ruby')
(4, 'python')
(4, 'java')
(4, 'c++')
(4, 'go')
(4, 'ruby')
(5, 'python')
(5, 'java')
(5, 'c++')
(5, 'go')
(5, 'ruby')
25
'''

combinations()- 获取迭代对象内指定数量的元素组合,不重复

迭代对象dev_list中有5个元素,将其中的元素各自组合起来,生成一个指定长度的子序列。如果指定的子序列长度为1,那么就会有5种可能,如果每个子序列的长度为2就会有6种可能,如果长度为5,那么就只有一种可能,也就是和原来的dev_list一致,如果指定的长度超过现有的元素个数,则不会输出任何内容:

# combinations() 获取迭代对象内指定数量的元素组合,不重复
dev_list = ("python", "java", "c++", "go", "ruby")
cm = itertools.combinations(dev_list, 3)
for c in cm:
    print(c)
'''
('python', 'java', 'c++')
('python', 'java', 'go')
('python', 'java', 'ruby')
('python', 'c++', 'go')
('python', 'c++', 'ruby')
('python', 'go', 'ruby')
('java', 'c++', 'go')
('java', 'c++', 'ruby')
('java', 'go', 'ruby')
('c++', 'go', 'ruby')
'''

combinations_with_replacement()- 获取迭代对象内指定数量的元素组合,包含重复项

# combinations_with_replacement() 获取迭代对象内指定数量的元素组合,包含重复项
cwr = itertools.combinations_with_replacement(iterable=dev_list, r=3)
for index, value in enumerate(cwr, 1):
    print(index, value)

当包含重复项的时候,一共有35种排列情况:

3.根据最短输入序列长度停止的迭代器

迭代器

实参

结果

示例

accumulate()

p [,func]

p0, p0+p1, p0+p1+p2, ...

accumulate([1,2,3,4,5]) --> 1 3 6 10 15

chain()

p, q, ...

p0, p1, ... plast, q0, q1, ...

chain('ABC', 'DEF') --> A B C D E F

chain.from_iterable()

iterable -- 可迭代对象

p0, p1, ... plast, q0, q1, ...

chain.from_iterable(['ABC', 'DEF']) --> A B C D E F

compress()

data, selectors

(d[0] if s[0]), (d[1] if s[1]), ...

compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F

dropwhile()

pred, seq

seq[n], seq[n+1], ... 从pred首次真值测试失败开始

dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1

filterfalse()

pred, seq

seq中pred(x)为假值的元素,x是seq中的元素。

filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8

groupby()

iterable[, key]

根据key(v)值分组的迭代器


islice()

seq, [start,] stop [, step]

seq[start:stop:step]中的元素

islice('ABCDEFG', 2, None) --> C D E F G

starmap()

func, seq

func(*seq[0]), func(*seq[1]), ...

starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000

takewhile()

pred, seq

seq[0], seq[1], ..., 直到pred真值测试失败

takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4

tee()

it, n

it1, it2, ... itn 将一个迭代器拆分为n个迭代器


zip_longest()

p, q, ...

(p[0], q[0]), (p[1], q[1]), ...

zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-

itertools.chain(*iterables)-多个可迭代对象组合迭代

chain 多个可迭代对象组合起来进行迭代

创建一个迭代器,它首先返回第一个可迭代对象中所有元素,接着返回下一个可迭代对象中所有元素,直到耗尽所有可迭代对象中的元素。可将多个序列处理为单个序列。大致相当于:

def chain(*iterables):
    # chain('ABC', 'DEF') --> A B C D E F
    for it in iterables:
        for element in it:
            yield element

例如:

# chain 多个可迭代对象组合起来进行迭代
testlist = [1, 2, 3, 4, 5]
dev_lan = ("python", "java", "c++", "go", "ruby")
itc = itertools.chain(testlist, dev_lan)
for i in itc:
    print(i)
'''
1
2
3
4
5
python
java
c++
go
ruby
'''

itertools.compress(data, selectors)-返回与真选择器元素相对应的数据元素

创建一个迭代器,它返回 data 中经 selectors 真值测试为 True 的元素。迭代器在两者较短的长度处停止。大致相当于:

def compress(data, selectors):
    # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
    return (d for d, s in zip(data, selectors) if s)

例如:迭代对象true_list中的元素,1表示真,0表示假,所以第1、3、5个元素就是真,2、4元素为假,也就会返回data中第1、3、5个元素,第2、4个元素不返回:

# itertools.compress(data, selectors) 返回与真选择器元素相对应的数据元素
true_list = [1, 0, 1, 0, 1]
cc = itertools.compress(data=["java", "ruby", "javascript", "html", "python"], selectors=true_list)
for c in cc:
    print(c)
'''
java
javascript
python
'''

itertools.dropwhile(predicate, iterable)-返回首次满足指定条件的元素之后的所有元素

创建一个迭代器,如果 predicate 为true,迭代器丢弃这些元素,然后返回其他元素。注意,迭代器在 predicate 首次为false之前不会产生任何输出,所以可能需要一定长度的启动时间。大致相当于:

def dropwhile(predicate, iterable):
    # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
    iterable = iter(iterable)
    for x in iterable:
        if not predicate(x):
            yield x
            break
    for x in iterable:
        yield x

返回满足首次指定条件的元素之后的所有元素,这句话听起来可能比较拗口,下面我们通过一个例子来解释,例如:迭代对象dev_list中有多个类型的元素,有整型、字符串型、列表型、元组型、浮点型。先通过匿名表达式lambda x: not isinstance(x, Iterable)来判断哪些元素不是可迭代对象,从列表元素可以看出:

  • "9999" 可迭代对象
  • 888 不可迭代对象
  • "python" 可迭代对象
  • (88, 77) 可迭代对象
  • [1, 2, 3] 可迭代对象
  • 0.999 不可迭代对象

使用dropwhile()方法对dev_list进行迭代判断,当找到第一个条件为True的选项(也就是第一个不是可迭代对象的元素)时,就停止,然后返回这个元素之后的所有元素。所以:"9999"元素是可迭代对象、结果为False,继续查找,888元素不是可迭代对象,满足条件,结果为True,停止查找,然后返回888这个元素后的所有元素:

# itertools.dropwhile(predicate, iterable) 返回满足首次指定条件的元素之后的所有元素
from collections.abc import Iterable

dev_list = ["9999", 888, "python", (88, 77), [1, 2, 3], 0.999]
iw = itertools.dropwhile(lambda x: not isinstance(x, Iterable), dev_list)

for i in iw:
    print(i)
'''
python
(88, 77)
[1, 2, 3]
0.999
'''

相关推荐

Java 泛型大揭秘:类型参数、通配符与最佳实践

引言在编程世界中,代码的可重用性和可维护性是至关重要的。为了实现这些目标,Java5引入了一种名为泛型(Generics)的强大功能。本文将详细介绍Java泛型的概念、优势和局限性,以及如何在...

K8s 的标签与选择器:流畅运维的秘诀

在Kubernetes的世界里,**标签(Label)和选择器(Selector)**并不是最炫酷的技术,但却是贯穿整个集群管理与运维流程的核心机制。正是它们让复杂的资源调度、查询、自动化运维变得...

哈希Hash算法:原理、应用(哈希算法 知乎)

原作者:Linux教程,原文地址:「链接」什么是哈希算法?哈希算法(HashAlgorithm),又称为散列算法或杂凑算法,是一种将任意长度的数据输入转换为固定长度输出值的数学函数。其输出结果通常被...

C#学习:基于LLM的简历评估程序(c# 简历)

前言在pocketflow的例子中看到了一个基于LLM的简历评估程序的例子,感觉还挺好玩的,为了练习一下C#,我最近使用C#重写了一个。准备不同的简历:image-20250528183949844查...

55顺位,砍41+14+3!季后赛也成得分王,难道他也是一名球星?

雷霆队最不可思议的新星:一个55号秀的疯狂逆袭!你是不是也觉得NBA最底层的55号秀,就只能当饮水机管理员?今年的55号秀阿龙·威金斯恐怕要打破你的认知了!常规赛阶段,这位二轮秀就像开了窍的天才,直接...

5分钟读懂C#字典对象(c# 字典获取值)

什么是字典对象在C#中,使用Dictionary类来管理由键值对组成的集合,这类集合被称为字典。字典最大的特点就是能够根据键来快速查找集合中的值,其键的定义不能重复,具有唯一性,相当于数组索引值,字典...

c#窗体传值(c# 跨窗体传递数据)

在WinForm编程中我们经常需要进行俩个窗体间的传值。下面我给出了两种方法,来实现传值一、在输入数据的界面中定义一个属性,供接受数据的窗体使用1、子窗体usingSystem;usingSyst...

C#入门篇章—委托(c#委托的理解)

C#委托1.委托的定义和使用委托的作用:如果要把方法作为函数来进行传递的话,就要用到委托。委托是一个类型,这个类型可以赋值一个方法的引用。C#的委托通过delegate关键字来声明。声明委托的...

C#.NET in、out、ref详解(c#.net framework)

简介在C#中,in、ref和out是用于修改方法参数传递方式的关键字,它们决定了参数是按值传递还是按引用传递,以及参数是否必须在传递前初始化。基本语义对比修饰符传递方式可读写性必须初始化调用...

C#广义表(广义表headtail)

在C#中,广义表(GeneralizedList)是一种特殊的数据结构,它是线性表的推广。广义表可以包含单个元素(称为原子),也可以包含另一个广义表(称为子表)。以下是一个简单的C#广义表示例代...

「C#.NET 拾遗补漏」04:你必须知道的反射

阅读本文大概需要3分钟。通常,反射用于动态获取对象的类型、属性和方法等信息。今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的。获取类型的成员Type类的GetMembe...

C#启动外部程序的问题(c#怎么启动)

IT&OT的深度融合是智能制造的基石。本公众号将聚焦于PLC编程与上位机开发。除理论知识外,也会结合我们团队在开发过程中遇到的具体问题介绍一些项目经验。在使用C#开发上位机时,有时会需要启动外部的一些...

全网最狠C#面试拷问:这20道题没答出来,别说你懂.NET!

在竞争激烈的C#开发岗位求职过程中,面试是必经的一道关卡。而一场高质量的面试,不仅能筛选出真正掌握C#和.NET技术精髓的人才,也能让求职者对自身技术水平有更清晰的认知。今天,就为大家精心准备了20道...

C#匿名方法(c#匿名方法与匿名类)

C#中的匿名方法是一种没有名称只有主体的方法,它提供了一种传递代码块作为委托参数的技术。以下是关于C#匿名方法的一些重要特点和用法:特点省略参数列表:使用匿名方法可省略参数列表,这意味着匿名方法...

C# Windows窗体(.Net Framework)知识总结

Windows窗体可大致分为Form窗体和MDI窗体,Form窗体没什么好细说的,知识点总结都在思维导图里面了,下文将围绕MDI窗体来讲述。MDI(MultipleDocumentInterfac...