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 相关文章推荐
python进阶教程之文本文件的读取和写入
Aug 29 Python
浅谈Python 中整型对象的存储问题
May 16 Python
Django数据库表反向生成实例解析
Feb 06 Python
python多进程使用及线程池的使用方法代码详解
Oct 24 Python
使用PM2+nginx部署python项目的方法示例
Nov 07 Python
flask框架路由常用定义方式总结
Jul 23 Python
Python 实现数组相减示例
Dec 27 Python
浅谈图像处理中掩膜(mask)的意义
Feb 19 Python
Selenium使用Chrome模拟手机浏览器方法解析
Apr 10 Python
为什么相对PHP黑python的更少
Jun 21 Python
UI自动化定位常用实现方法代码示例
Oct 27 Python
python中类与对象之间的关系详解
Dec 16 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
繁体中文转换为简体中文的PHP函数
2006/10/09 PHP
PHP下用rmdir实现删除目录的三种方法小结
2008/04/20 PHP
php实现把url转换迅雷thunder资源下载地址的方法
2014/11/07 PHP
PHP 获取客户端 IP 地址的方法实例代码
2018/11/11 PHP
jQuery源码分析-03构造jQuery对象-工具函数
2011/11/14 Javascript
jquery分页插件AmSetPager(自写)
2013/04/15 Javascript
jquery插件之定时查询待处理任务数量
2014/05/01 Javascript
js实现无限级树形导航列表效果代码
2015/09/23 Javascript
详解JavaScript的流程控制语句
2015/11/30 Javascript
详解js界面跳转与值传递
2016/11/22 Javascript
js中数组插入、删除元素操作的方法
2017/02/15 Javascript
JavaScript中双符号的运算详解
2017/03/12 Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
Vue引用Swiper4插件无法重写分页器样式的解决方法
2018/09/27 Javascript
浅谈express.js框架中间件(middleware)
2019/04/07 Javascript
[04:10]DOTA2英雄梦之声_第11期_圣堂刺客
2014/06/21 DOTA
[01:01:31]2018DOTA2亚洲邀请赛3月29日小组赛B组 Mineski VS paiN
2018/03/30 DOTA
python数组过滤实现方法
2015/07/27 Python
python3实现跳一跳点击跳跃
2018/01/08 Python
查看Django和flask版本的方法
2018/05/14 Python
pycharm恢复默认设置或者是替换pycharm的解释器实例
2018/10/29 Python
python 使用 requests 模块发送http请求 的方法
2018/12/09 Python
pycharm+PyQt5+python最新开发环境配置(踩坑)
2019/02/11 Python
Django框架自定义模型管理器与元选项用法分析
2019/07/22 Python
详解如何用TensorFlow训练和识别/分类自定义图片
2019/08/05 Python
Parfumdreams芬兰:购买香水和化妆品
2021/02/13 全球购物
自考毕业生自我鉴定
2013/11/04 职场文书
2014学校庆三八妇女节活动总结
2014/03/01 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
5s标语大全
2014/06/23 职场文书
人力资源管理毕业求职信
2014/08/05 职场文书
小学生春游活动方案
2014/08/20 职场文书
个人求职意向书
2015/05/11 职场文书
幼儿园心得体会范文
2016/01/21 职场文书
《云雀的心愿》教学反思
2016/02/23 职场文书
MySQL 全文索引使用指南
2021/05/25 MySQL