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之从if开始语句的征程
Sep 14 Python
Python实现查找系统盘中需要找的字符
Jul 14 Python
详解python的数字类型变量与其方法
Nov 20 Python
python 统计一个列表当中的每一个元素出现了多少次的方法
Nov 14 Python
对Python实现累加函数的方法详解
Jan 23 Python
python实现简单颜色识别程序
Feb 19 Python
Python通过Pillow实现图片对比
Apr 29 Python
一些关于python 装饰器的个人理解
Aug 31 Python
Python内存泄漏和内存溢出的解决方案
Sep 26 Python
python爬虫判断招聘信息是否存在的实例代码
Nov 20 Python
Python 爬取淘宝商品信息栏目的实现
Feb 06 Python
python制作图形界面的2048游戏, 基于tkinter
Apr 06 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输出缓存(output_buffering)的深入理解
2013/06/13 PHP
去除php注释和去除空格函数分享
2014/03/13 PHP
Yii2中简单的场景使用介绍
2017/06/02 PHP
PHP设计模式之组合模式定义与应用示例
2020/02/01 PHP
JavaScript prototype 使用介绍
2013/08/29 Javascript
window.location不跳转的问题解决方法
2014/04/17 Javascript
在JS数组特定索引处指定位置插入元素的技巧
2014/08/24 Javascript
jQuery实现切换字体大小的方法
2015/03/10 Javascript
jQuery实现的支持IE的html滑动条
2015/03/16 Javascript
Jquery效果大全之制作电脑健康体检得分特效附源码下载
2015/11/02 Javascript
Bootstrap多级导航栏(级联导航)的实现代码
2016/03/08 Javascript
jquery 抽奖小程序实现代码
2016/10/12 Javascript
微信小程序 wxapp导航 navigator详解
2016/10/31 Javascript
JS前端开发判断是否是手机端并跳转操作(小结)
2017/02/05 Javascript
如何通过非数字与字符的方式实现PHP WebShell详解
2017/07/02 Javascript
vue拦截器实现统一token,并兼容IE9验证功能
2018/04/26 Javascript
基于jQuery ztree实现表格风格的树状结构
2018/08/31 jQuery
详解基于React.js和Node.js的SSR实现方案
2019/03/21 Javascript
jquery实现的放大镜效果示例
2020/02/24 jQuery
Javascript Symbol原理及使用方法解析
2020/10/22 Javascript
[36:05]DOTA2亚洲邀请赛 3.31 小组赛 A组 Liquid vs Optic
2018/04/01 DOTA
python 实现list或string按指定分段
2019/12/25 Python
Python Pivot table透视表使用方法解析
2020/09/11 Python
python 多线程爬取壁纸网站的示例
2021/02/20 Python
Wiggle澳大利亚:自行车、跑步、游泳商店
2020/11/07 全球购物
什么是会话Bean
2015/05/14 面试题
京剧自荐信
2014/01/26 职场文书
进步之星获奖感言
2014/02/22 职场文书
《将心比心》教学反思
2014/04/08 职场文书
法制教育演讲稿
2014/09/10 职场文书
亲戚关系证明
2015/06/24 职场文书
新入职员工工作总结
2015/10/15 职场文书
广播稿:校园广播稿范文
2019/04/17 职场文书
考教师资格证不要错过的4个最佳时机
2019/07/17 职场文书
2019年关于小学生课外阅读情况的分析报告
2019/12/02 职场文书
HAM-2000摩机图
2021/04/22 无线电