将不规则的Python多维数组拉平到一维的方法实现


Posted in Python onJanuary 11, 2021

原始需求:

将不规则的Python多维数组拉平到一维的方法实现

例如有一个列表:

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

希望把它转换成下面这种形式:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

其实这个非常简单,我将分享三个一行式代码来解决这个问题。

但如果是下面这种不规则的多维列表:

l = [[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]

我们想将它拉平到一维列表:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

又该怎么实现呢?

文末将演示通过递归或栈来实现深度优先遍历策略从而解决这个问题。

使用numpy拉平数组

import numpy as np
np.array(l).flatten().tolist()

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

使用python拉平数组

使用numpy数组拉平数组,其实很受限,一旦列表内部每个元素的长度不一致,numpy就不好使了:

l = [[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]
np.array(l).flatten().tolist()

D:\Anaconda3\lib\site-packages\ipykernel_launcher.py:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray

结果:

[[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]

这时我们可以通过python的itertools来实现高效的操作:

import itertools
list(itertools.chain(*l))

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

当然还有一种更高级的操作方法是直接使用sum函数:

sum(l, [])

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

你可能一脸懵逼,为什么sum函数可以实现列表的拉平?下面我翻译一下,这段代码实际做了什么:

result = []
for i in l:
  result += i
result

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

将不规则多维数组拉平到1维

例如,对于下面这个复杂的列表:

l = [[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]
l

结果:

[[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]

这样的列表,对于上面的方法来说已经都不好使了,这个时候怎么办呢?

当然对于这种长度不长的列表,我们可以玩点小技巧:

list_str = str(l).replace("[", "").replace("]", "")
eval(f"[{list_str}]")

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

当然,使用正则替换更佳:

import re
eval(re.sub("(?!^)\[|\](?!$)", "", str(l)))

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

原理就是先将这个列表转成普通的字符串,再将所有的[]字符都去掉,再转成单维列表的字符串形式之后,用eval函数进行解析。但这种方式在列表足够长的时候显然是不合适的,会出现效率低下的问题。

深度优先遍历策略拉平多维数组

下面我介绍一个正常的解决这个问题的办法,那就是使用深度优先遍历策略来解决这个问题,当然如果你对拉平的结果没有顺序的要求还可以使用广度优先遍历的策略。

深度优先遍历策略,最简单直接的思路是使用递归来实现:

def flatten(items, result=[]):
  for item in items:
    if isinstance(item, list):
      flatten(item, result)
    else:
      result.append(item)


result = []
flatten(l, result)
result

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

虽然递归可能出现调用栈过多导致性能下降或程序挂掉,但Python可以借助生成器让递归调用变成普通调用:

def flatten(items):
  for item in items:
    if isinstance(item, list):
      yield from flatten(item)
    else:
      yield item


result = [e for e in flatten(l)]
result

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

而如果我们想不使用递归或生成器类递归,可以直接借助一个栈来实现。

为了保证结果是原有的顺序,我们把左端作为栈顶,而数组不适合删除左端的数据,所以可以使用deque来作为栈。

首先,我们需要将原列表转换为deque,下面是处理代码:

from collections import deque

stack = deque(l)
result = []
while len(stack) != 0:
  item = stack.popleft()
  if isinstance(item, list):
    for e in reversed(item):
      stack.appendleft(e)
  else:
    result.append(item)
result

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

如果我们将原列表作为一个右端为栈顶的栈,可以通过向结果左端插入数据来保持原有的顺序:

from collections import deque

stack = l.copy()
result = deque()
while len(stack) != 0:
  item = stack.pop()
  if isinstance(item, list):
    for e in item:
      stack.append(e)
  else:
    result.appendleft(item)
result = list(result)
result

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

小结

想不到小小的列表拉平还有这么多学问,希望今天的分享能够对让你学有所获。

到此这篇关于将不规则的Python多维数组拉平到一维的方法实现的文章就介绍到这了,更多相关Python多维数组拉平到一维内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python Pygame的具体使用讲解
Nov 03 Python
Python实现生成随机日期字符串的方法示例
Dec 25 Python
python数字图像处理之高级形态学处理
Apr 27 Python
Python3日期与时间戳转换的几种方法详解
Jun 04 Python
python2和python3实现在图片上加汉字的方法
Aug 22 Python
Python列表元素常见操作简单示例
Oct 25 Python
python实现将视频按帧读取到自定义目录
Dec 10 Python
python 实现批量替换文本中的某部分内容
Dec 13 Python
Python中base64与xml取值结合问题
Dec 22 Python
Python编程快速上手——强口令检测算法案例分析
Feb 29 Python
Python selenium使用autoIT上传附件过程详解
May 26 Python
python字符串的index和find的区别详解
Jun 20 Python
python用分数表示矩阵的方法实例
Jan 11 #Python
termux中matplotlib无法显示中文问题的解决方法
Jan 11 #Python
完美解决Pycharm中matplotlib画图中文乱码问题
Jan 11 #Python
Python脚本调试工具安装过程
Jan 11 #Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
Jan 11 #Python
Jupyter Notebook 远程访问配置详解
Jan 11 #Python
jupyter notebook远程访问不了的问题解决方法
Jan 11 #Python
You might like
将时间以距今多久的形式表示,PHP,js双版本
2012/09/25 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(九)
2014/06/24 PHP
PHP实现的下载远程图片自定义函数分享
2015/01/28 PHP
php-fpm超时时间设置request_terminate_timeout资源问题分析
2019/09/27 PHP
Avengerls vs KG BO3 第一场2.18
2021/03/10 DOTA
js 刷新页面的代码小结 推荐
2010/04/02 Javascript
多个checkbox被选中时如何判断是否有自己想要的
2014/09/22 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
一篇看懂vuejs的状态管理神器 vuex状态管理模式
2017/04/20 Javascript
Vue.js中兄弟组件之间互相传值实例
2017/06/01 Javascript
详解vue-resource promise兼容性问题
2017/06/20 Javascript
Bootstrap按钮组实例详解
2017/07/03 Javascript
angular实现spa单页面应用实例
2017/07/10 Javascript
使用Webpack提高Vue.js应用的方式汇总(四种)
2017/07/10 Javascript
JavaScript登录验证基础教程
2017/11/01 Javascript
vue实现百度下拉列表交互操作示例
2019/03/12 Javascript
vue实现直播间点赞飘心效果的示例代码
2019/09/20 Javascript
在js文件中引入(调用)另一个js文件的三种方法
2020/09/11 Javascript
Python通过RabbitMQ服务器实现交换机功能的实例教程
2016/06/29 Python
Python使用Scrapy爬虫框架全站爬取图片并保存本地的实现代码
2018/03/04 Python
Python实现二维数组输出为图片
2018/04/03 Python
python+pandas分析nginx日志的实例
2018/04/28 Python
关于阿里云oss获取sts凭证 app直传 python的实例
2019/08/20 Python
python中有关时间日期格式转换问题
2019/12/25 Python
使用Python爬虫库requests发送表单数据和JSON数据
2020/01/25 Python
总结Pyinstaller的坑及终极解决方法(小结)
2020/09/21 Python
CSS3中border-radius属性设定圆角的使用技巧
2016/05/10 HTML / CSS
英国家庭、花园、汽车和移动解决方案:Easylife Group
2018/05/23 全球购物
Beauty Expert美国/加拿大:购买奢侈美容产品
2018/12/05 全球购物
一份比较全的PHP面试题
2016/07/29 面试题
七年级地理教学反思
2014/01/26 职场文书
红旗团支部事迹材料
2014/01/27 职场文书
创业计划书详解
2019/07/19 职场文书
分享:关于学习的励志名言赏析
2019/08/16 职场文书
中国现代文学之经典散文三篇
2019/09/18 职场文书
导游词之上海杜莎夫人蜡像馆
2019/11/22 职场文书