将不规则的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实现的最近最少使用算法
Jul 10 Python
详解Django框架中用户的登录和退出的实现
Jul 23 Python
Python工程师面试必备25条知识点
Jan 17 Python
Django重装mysql后启动报错:No module named ‘MySQLdb’的解决方法
Apr 22 Python
正确理解Python中if __name__ == '__main__'
Jan 24 Python
python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)
Jun 27 Python
python GUI库图形界面开发之PyQt5多线程中信号与槽的详细使用方法与实例
Mar 08 Python
python selenium操作cookie的实现
Mar 18 Python
Jupyter Notebook折叠输出的内容实例
Apr 22 Python
Python调用shell命令常用方法(4种)
May 11 Python
python3爬虫中多线程的优势总结
Nov 24 Python
python turtle绘制多边形和跳跃和改变速度特效
Mar 16 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 计算代码执行耗时的代码修正网上普遍错误
2011/05/14 PHP
XAMPP安装与使用方法详细解析
2013/11/27 PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
2017/05/20 PHP
PHP SPL 被遗落的宝石【SPL应用浅析】
2018/04/20 PHP
PHP7 新增常量
2021/03/09 PHP
学习JS面向对象成果 借国庆发布个最新作品与大家交流
2009/10/03 Javascript
javascript 基础篇2 数据类型,语句,函数
2012/03/14 Javascript
js jquery分别实现动态的文件上传操作按钮的添加和删除
2014/01/13 Javascript
用jQuery模拟select下拉框的简单示例代码
2014/01/26 Javascript
javascript中call,apply,bind的用法对比分析
2015/02/12 Javascript
深入解析JavaScript中的数字对象与字符串对象
2015/10/21 Javascript
angular中实现li或者某个元素点击变色的两种方法
2017/07/27 Javascript
js禁止表单重复提交
2017/08/29 Javascript
基于node.js实现微信支付退款功能
2017/12/19 Javascript
jquery中ajax请求后台数据成功后既不执行success也不执行error的完美解决方法
2017/12/24 jQuery
详解Vue中使用插槽(slot)、聚类插槽
2019/04/12 Javascript
浅谈VUE防抖与节流的最佳解决方案(函数式组件)
2019/05/22 Javascript
Vue 实现html中根据类型显示内容
2019/10/28 Javascript
javascript canvas API内容整理
2020/02/16 Javascript
vue实现tab栏点击高亮效果
2020/08/19 Javascript
js实现滑动进度条效果
2020/08/21 Javascript
[02:45]DOTA2英雄敌法师基础教程
2013/11/25 DOTA
[52:40]完美世界DOTA2联赛PWL S2 Magma vs GXR 第一场 11.29
2020/12/02 DOTA
python翻译软件实现代码(使用google api完成)
2013/11/26 Python
解决python3 urllib中urlopen报错的问题
2017/03/25 Python
Django使用模板后无法找到静态资源文件问题解决
2019/07/19 Python
Python流程控制语句的深入讲解
2020/06/15 Python
蒂芙尼澳大利亚官方网站:Tiffany&Co. Australia
2017/08/27 全球购物
阳光体育:Sunny Sports(购买露营和远足设备)
2018/08/07 全球购物
Skyscanner香港:机票比价, 平机票和廉价航空机票预订
2020/02/07 全球购物
通信工程毕业生求职信
2013/11/16 职场文书
实习鉴定范文
2013/12/19 职场文书
大学生职业生涯设计书
2014/01/02 职场文书
2014年乡镇工会工作总结
2014/12/02 职场文书
Android基于Fresco实现圆角和圆形图片
2022/04/01 Java/Android
阿里云 Windows server 2019 配置FTP
2022/04/28 Servers