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的Django中django-userena组件的简单使用教程
May 30 Python
python 使用get_argument获取url query参数
Apr 28 Python
python 连接sqlite及简单操作
Jun 30 Python
Python连接phoenix的方法示例
Sep 29 Python
使用sklearn之LabelEncoder将Label标准化的方法
Jul 11 Python
对Python2与Python3中__bool__方法的差异详解
Nov 01 Python
对pandas将dataframe中某列按照条件赋值的实例讲解
Nov 29 Python
pyqt5之将textBrowser的内容写入txt文档的方法
Jun 21 Python
扩展Django admin的list_filter()可使用范围方法
Aug 21 Python
matplotlib quiver箭图绘制案例
Apr 17 Python
python析构函数用法及注意事项
Jun 22 Python
Python 使用 Frame tkraise() 方法在 Tkinter 应用程序中的Frame之间切换
Apr 24 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获取类中常量,属性,及方法列表的方法
2009/04/09 PHP
php写的简易聊天室代码
2011/06/04 PHP
PHP使用CURL实现对带有验证码的网站进行模拟登录的方法
2014/07/23 PHP
php保存二进制原始数据为图片的程序代码
2014/10/14 PHP
php字符串分割函数用法实例
2015/03/17 PHP
PHP空值检测函数与方法汇总
2017/11/19 PHP
php使用redis的几种常见操作方式和用法示例
2020/02/20 PHP
JavaScript 替换Html标签实现代码
2009/10/14 Javascript
三种动态加载js的jquery实例代码另附去除js方法
2014/04/30 Javascript
avalonjs实现仿微博的图片拖动特效
2015/05/06 Javascript
javascript设置页面背景色及背景图片的方法
2015/12/29 Javascript
JavaScript通过代码调用Flash显示的方法
2016/02/02 Javascript
JavaScript获取ul中li个数的方法
2017/02/13 Javascript
基于js中style.width与offsetWidth的区别(详解)
2017/11/12 Javascript
微信小程序实现随机验证码功能
2018/12/20 Javascript
java遇到微信小程序 "支付验证签名失败" 问题解决
2019/12/22 Javascript
JS实现页面数据懒加载
2020/02/13 Javascript
Python中的字符串操作和编码Unicode详解
2017/01/18 Python
浅谈Python中的可变对象和不可变对象
2017/07/07 Python
酷! 程序员用Python带你玩转冲顶大会
2018/01/17 Python
python基于http下载视频或音频
2018/06/20 Python
python读取Excel实例详解
2018/08/17 Python
python简单实现9宫格图片实例
2020/09/03 Python
python 绘制场景热力图的示例
2020/09/23 Python
纯CSS实现右侧底部悬浮效果(悬浮QQ、微信、微博、邮箱等联系方式)
2015/04/24 HTML / CSS
诗普兰迪官方网站:Splendid
2018/09/18 全球购物
公司财务工作总结的自我评价
2013/11/23 职场文书
高中生学习的自我评价
2013/12/14 职场文书
给幼儿园老师的表扬信
2014/01/19 职场文书
高三自我评价
2014/02/01 职场文书
文化活动实施方案
2014/03/28 职场文书
交通事故协议书范文
2014/04/16 职场文书
大学生学年个人总结
2015/02/15 职场文书
开业庆典嘉宾致辞
2015/08/01 职场文书
岗位聘任协议书
2015/09/21 职场文书
navicat 连接Ubuntu虚拟机的mysql的操作方法
2022/04/02 MySQL