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 base64 decode incorrect padding错误解决方法
Jan 08 Python
python中sys.argv参数用法实例分析
May 20 Python
Linux CentOS7下安装python3 的方法
Jan 21 Python
win10下tensorflow和matplotlib安装教程
Sep 19 Python
解决Python 使用h5py加载文件,看不到keys()的问题
Feb 08 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
Jul 19 Python
Django 开发环境与生产环境的区分详解
Jul 26 Python
Python程序暂停的正常处理方法
Nov 07 Python
Python3 解决读取中文文件txt编码的问题
Dec 20 Python
python解析xml文件方式(解析、更新、写入)
Mar 05 Python
python使用paramiko实现ssh的功能详解
Mar 06 Python
Python实现寻找回文数字过程解析
Jun 09 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
收音机的保养
2021/03/01 无线电
利用递归把多维数组转为一维数组的函数
2006/10/09 PHP
超级实用的7个PHP代码片段分享
2012/01/05 PHP
PHP判断文件是否存在、是否可读、目录是否存在的代码
2012/10/03 PHP
PHP常用编译参数中文说明
2014/09/27 PHP
JavaScript 异步调用框架 (Part 1 - 问题 & 场景)
2009/08/03 Javascript
自己的js工具 Event封装
2009/08/21 Javascript
JavaScipt中的Math.ceil() 、Math.floor() 、Math.round() 三个函数的理解
2010/04/29 Javascript
调整小数的格式保留小数点后两位
2014/05/14 Javascript
JavaScript实现三阶幻方算法谜题解答
2014/12/29 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
JS实现网页右侧带动画效果的伸缩窗口代码
2015/10/29 Javascript
详解Angularjs中的依赖注入
2016/03/11 Javascript
在html中引入外部js文件,并调用带参函数的方法
2016/10/31 Javascript
bootstrap fileinput 上传插件的基础使用
2017/02/17 Javascript
vue使用watch 观察路由变化,重新获取内容
2017/03/08 Javascript
Iscrool下拉刷新功能实现方法(推荐)
2017/06/26 Javascript
解决使用Vue.js显示数据的时,页面闪现原始代码的问题
2018/02/11 Javascript
解决vue this.$forceUpdate() 处理页面刷新问题(v-for循环值刷新等)
2018/07/26 Javascript
laravel实现中文和英语互相切换的例子
2019/09/30 Javascript
[00:52]DOTA2第二届亚洲邀请赛预选赛宣传片
2017/01/13 DOTA
python实现的防DDoS脚本
2011/02/08 Python
Python中内置数据类型list,tuple,dict,set的区别和用法
2015/12/14 Python
selenium处理元素定位点击无效问题
2019/06/12 Python
Python字符串和正则表达式中的反斜杠('\')问题详解
2019/09/03 Python
浅析python字符串前加r、f、u、l 的区别
2021/01/24 Python
如何给HTML标签中的文本设置修饰线
2019/11/18 HTML / CSS
公务员职务工作的自我评价
2013/11/01 职场文书
员工薪酬福利制度
2014/01/17 职场文书
摄影专业毕业生求职信
2014/03/13 职场文书
纪检监察建议书
2014/05/19 职场文书
职工擅自离岗检讨书
2014/09/23 职场文书
党建工作整改措施
2014/10/28 职场文书
班主任工作实习计划
2015/01/16 职场文书
小学生禁毒教育心得体会
2016/01/15 职场文书
在Windows Server 2012上安装 .NET Framework 3.5 所遇到的问题
2022/04/29 Servers