Python合并指定范围连续整数列表的简便方法及相关疑问
需求背景
需要构造包含多段连续整数的列表,示例结果如下:
[1,2,3,4,5,6,7, 15,16,17,18,19, 56,57,58,59]
已知各段整数的起止值,最初的实现方式如下:
ranges = (range(1,8), range(15,20), range(56,60)) Y = sum( [ list(x) for x in ranges ] )
该写法可行但代码繁琐,且用sum()拼接序列的方式可读性差。对比MATLAB的简洁实现:
Y = [ 1:7, 15:19, 56:59 ]
现寻求更优的Python实现方式(支持NumPy),并解答以下疑问:为何使用生成器表达式传入sum()会报错?
报错代码:
Y = sum( (list(x) for x in ranges) )
报错信息:
TypeError: unsupported operand types for +: 'int' and 'list'
疑惑点:sum()的默认初始值为何是0而非空列表[]?
优化实现方式
原生Python实现:用itertools.chain拼接序列
使用itertools.chain可以高效拼接多个迭代器,语义明确,可读性远优于sum():
from itertools import chain ranges = (range(1,8), range(15,20), range(56,60)) # 方式1:解包ranges传入chain Y = list(chain(*ranges)) # 方式2:用chain.from_iterable避免解包,更适合可迭代对象的序列 Y = list(chain.from_iterable(ranges))
chain专门用于串联多个迭代器,无需先将每个range转为列表,性能更优,代码意图清晰。
NumPy实现:用np.r_模拟MATLAB风格
NumPy的np.r_可以实现和MATLAB几乎一致的简洁写法,完美贴合需求:
import numpy as np # 直接按段指定范围,左闭右开规则与Python一致 Y = np.r_[1:8, 15:20, 56:60] # 若需要转为普通Python列表,添加tolist() Y_list = Y.tolist()
np.r_会自动将各段范围拼接为一个NumPy数组,写法简洁直观,和MATLAB的语法高度相似。
sum()使用生成器表达式报错的原因
sum()函数的设计初衷是对数值类型求和,因此默认初始值为0。当你传入生成器表达式(list(x) for x in ranges)时,sum()会先执行0 + 第一个列表的操作,而整数与列表不支持+运算,因此触发TypeError。
如果一定要用sum()拼接列表,必须显式指定初始值为空列表[],让sum()从空列表开始依次拼接每个列表:
Y = sum( (list(x) for x in ranges), [] )
但这种写法依然不推荐,因为sum()的语义是求和,用来拼接序列会混淆代码意图,远不如itertools.chain清晰。
内容的提问来源于stack exchange,提问作者Sanjay Manohar

