Python 把两层列表展开平铺成一层(5种实现方式)


Posted in Python onApril 07, 2021

这几天和同事在讨论,如何用 Python 写出优雅的让列表中的列表展开,变成扁平化的列表。

例如

# 期望输入
input = [[('A', 1), ('B', 2)], [('C', 3), ('D', 4)]]
 
# 期望输出
output = [('A', 1), ('B', 2), ('C', 3), ('D', 4)]

map 函数合并

>>> new = []; map(new.extend, input); new
[None, None]
[('A', 1), ('B', 2), ('C', 3), ('D', 4)]

这个方法看上去还可以,但是有个致命的缺点,就是map函数会返回值,并且这个返回值是没有用的。另外还需要提前声明一个变量,从代码的简洁性上,不够简洁优雅。

sum 函数合并

>>> sum(input, [])
[('A', 1), ('B', 2), ('C', 3), ('D', 4)]

这个看上去很简洁,不过有类似字符串累加的性能陷阱。后面有性能对比。

reduce 函数

>>> reduce(list.__add__, input)
[('A', 1), ('B', 2), ('C', 3), ('D', 4)]

做序列的累加操作。也是有累加的性能陷阱。

列表推导式

>>> [item for sublist in input for item in sublist]
[('A', 1), ('B', 2), ('C', 3), ('D', 4)]

列表推导式,看着有些长,而且还要for循环两次,变成一行理解需要费劲一些,没有那么直观。

itertools 类库

>>> list(itertools.chain(*input))
[('A', 1), ('B', 2), ('C', 3), ('D', 4)]

通过第三方类库类实现的,相比其他的几个实现,看着还算比较优雅。最后的性能发现居然还很高。

性能大对比

python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(list.__add__,l)'
1000 loops, best of 3: 547 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 509 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 52.8 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99; import itertools;' 'list(itertools.chain(*l))'
10000 loops, best of 3: 35.9 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'new = []; map(new.extend, l); new'
10000 loops, best of 3: 34.1 usec per loop

欢迎大家共同探讨优雅的的实现和性能的优化。

补充:python 将(含嵌套的)dict平铺展开

话不多说,直接上代码:

def prefix_dict(di_, prefix_s=''):
  """
  把字典的每个key都带上前缀prefix_s
  :param di_:
  :param prefix_s:
  :return:
  """
  return {prefix_s + k: v for k, v in di_.items()} 
 
def spear_dict(di_, con_s='.'):
  """
  展开dict(如果下层还是dict),需要递归,展开到下层的数据类型不是字典为止
  可能实用的地方:将文档类的数据格式化成更加关系化的样子可能有用
  :param di_: 输入字典
  :param con_s: 层级间的连接符号
  :return: 深度不大于1的字典,嵌套的其他数据类型照旧
  """
  ret_di = {}
  for k, v in di_.items():
    if type(v) is dict:
      v = spear_dict(v)
      # 这里或许有不写到这一层的更好写法
      # for k_, v_ in v.items():
      #   ret_di.update({con_s.join([k, k_]): v_})
      ret_di.update(prefix_dict(v, prefix_s=k + con_s))
    else:
      ret_di.update({k: v})
  return ret_di
>>> di_
{'title': '新田商业街', 'reliability': 7, 'addressComponents': {'streetNumber': '', 'city': '深圳市', 'street': '', 'province': '广东省', 'district': '龙华区'}, 'location': {'lng': 114.09127044677734, 'lat': 22.700519561767578}, 'adInfo': {'adcode': '440309'}, 'level': 11, 'more_deep': {'loca': {'lng': 114.09127044677734, 'lat': 22.700519561767578}}}
>>> spear_dict(di_)
{'title': '新田商业街', 'reliability': 7, 'addressComponents.streetNumber': '', 'addressComponents.city': '深圳市', 'addressComponents.street': '', 'addressComponents.province': '广东省', 'addressComponents.district': '龙华区', 'location.lng': 114.09127044677734, 'location.lat': 22.700519561767578, 'adInfo.adcode': '440309', 'level': 11, 'more_deep.loca.lng': 114.09127044677734, 'more_deep.loca.lat': 22.700519561767578}
spear_dict(di_, '_')
{'title': '新田商业街', 'reliability': 7, 'addressComponents_streetNumber': '', 'addressComponents_city': '深圳市', 'addressComponents_street': '', 'addressComponents_province': '广东省', 'addressComponents_district': '龙华区', 'location_lng': 114.09127044677734, 'location_lat': 22.700519561767578, 'adInfo_adcode': '440309', 'level': 11, 'more_deep_loca.lng': 114.09127044677734, 'more_deep_loca.lat': 22.700519561767578}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Python 相关文章推荐
python2.7删除文件夹和删除文件代码实例
Dec 18 Python
Python3下错误AttributeError: ‘dict’ object has no attribute’iteritems‘的分析与解决
Jul 06 Python
运行django项目指定IP和端口的方法
May 14 Python
Sanic框架配置操作分析
Jul 17 Python
对numpy中的where方法嵌套使用详解
Oct 31 Python
对python条件表达式的四种实现方法小结
Jan 30 Python
numpy中的meshgrid函数的使用
Jul 31 Python
Django框架 信号调度原理解析
Sep 04 Python
浅析Django中关于session的使用
Dec 30 Python
PyCharm 2020 激活到 2100 年的教程
Mar 25 Python
Python3基于plotly模块保存图片表格
Aug 03 Python
PyQt5多线程防卡死和多窗口用法的实现
Sep 15 Python
Python获取百度热搜的完整代码
详解Python小数据池和代码块缓存机制
Apr 07 #Python
浅谈Python列表嵌套字典转化的问题
Apr 07 #Python
python pyhs2 的安装操作
Apr 07 #Python
python3 sqlite3限制条件查询的操作
Apr 07 #Python
python实现高效的遗传算法
解决hive中导入text文件遇到的坑
Apr 07 #Python
You might like
?繁体转换的class
2006/10/09 PHP
php中获得视频时间总长度的另一种方法
2011/09/15 PHP
php单一接口的实现方法
2015/06/20 PHP
PHP中filter函数校验数据的方法详解
2015/07/31 PHP
php获取字符串前几位的实例(substr返回字符串的子串用法)
2017/03/08 PHP
php5.5使用PHPMailer-5.2发送邮件的完整步骤
2018/10/14 PHP
收藏一些不常用,但是有用的代码
2007/03/12 Javascript
jquery图片放大镜功能的实例代码
2013/03/26 Javascript
JavaScript调用客户端的可执行文件(示例代码)
2013/11/28 Javascript
BootStrap入门教程(二)之固定的内置样式
2016/09/19 Javascript
JQuery页面随滚动条动态加载效果的简单实现(推荐)
2017/02/08 Javascript
JS图片延迟加载插件LazyImgv1.0用法分析【附demo源码下载】
2017/09/04 Javascript
微信小程序页面间跳转传参方式总结
2019/06/13 Javascript
[03:11]完美世界DOTA2联赛PWL DAY8集锦
2020/11/09 DOTA
python制作小说爬虫实录
2017/08/14 Python
使用PIL(Python-Imaging)反转图像的颜色方法
2019/01/24 Python
python 判断矩阵中每行非零个数的方法
2019/01/26 Python
Python3爬虫之自动查询天气并实现语音播报
2019/02/21 Python
Python实现数值积分方式
2019/11/20 Python
Python如何用wx模块创建文本编辑器
2020/06/07 Python
python属于解释型语言么
2020/06/15 Python
Python爬虫防封ip的一些技巧
2020/08/06 Python
css3实现信纸/同学录效果的示例代码
2018/12/11 HTML / CSS
分享一个页面平滑滚动小技巧(推荐)
2019/10/23 HTML / CSS
荷兰皇家航空公司中国官网:KLM中国
2017/12/13 全球购物
应届生个人求职信模板
2013/11/26 职场文书
新员工欢迎词
2014/01/12 职场文书
物理专业本科生自荐信
2014/01/30 职场文书
新闻编辑自荐书范文
2014/02/12 职场文书
新年抽奖获奖感言
2014/03/02 职场文书
个人学习群众路线心得体会
2014/11/05 职场文书
2015年服务员工作总结
2015/04/08 职场文书
《植物妈妈有办法》教学反思
2016/02/23 职场文书
MongoDB balancer的使用详解
2021/04/30 MongoDB
深入理解Pytorch微调torchvision模型
2021/11/11 Python
Java tomcat手动配置servlet详解
2021/11/27 Java/Android