将不规则的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 相关文章推荐
python2.7删除文件夹和删除文件代码实例
Dec 18 Python
python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享
Jul 09 Python
Python多进程编程技术实例分析
Sep 16 Python
python按照多个字符对字符串进行分割的方法
Mar 17 Python
微信跳一跳小游戏python脚本
Jan 05 Python
python3 selenium自动化 下拉框定位的例子
Aug 23 Python
Python动态导入模块和反射机制详解
Feb 18 Python
keras中的loss、optimizer、metrics用法
Jun 15 Python
python基于opencv 实现图像时钟
Jan 04 Python
windows系统Tensorflow2.x简单安装记录(图文)
Jan 18 Python
Django如何与Ajax交互
Apr 29 Python
python多次执行绘制条形图
Apr 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
建立动态的WML站点(三)
2006/10/09 PHP
phpMyAdmin下载、安装和使用入门教程
2007/05/31 PHP
PHP 清空varnish 缓存的详解(包括指定站点下的)
2013/06/20 PHP
PHP截取指定图片大小的方法
2014/12/10 PHP
PHP学习笔记(三):数据类型转换与常量介绍
2015/04/17 PHP
Laravel监听数据库访问,打印SQL的例子
2019/10/24 PHP
js调试工具 Javascript Debug Toolkit 2.0.0版本发布
2008/12/02 Javascript
缓动函数requestAnimationFrame 更好的实现浏览器经动画
2012/12/07 Javascript
FireBug 调试JS入门教程 如何调试JS
2013/12/23 Javascript
js+css实现的简单易用兼容好的分页
2013/12/30 Javascript
js 触发select onchange事件代码
2014/03/20 Javascript
node.js中的fs.rmdir方法使用说明
2014/12/16 Javascript
js获取会话框prompt的返回值的方法
2015/01/10 Javascript
js获取时间精确到秒(年月日)
2016/03/16 Javascript
jQuery Select下拉框操作小结(推荐)
2016/07/22 Javascript
纯前端JavaScript实现Excel IO案例分享
2016/08/26 Javascript
jstl中判断list中是否包含某个值的简单方法
2016/10/14 Javascript
Vue-Router进阶之滚动行为详解
2017/09/13 Javascript
详解Chai.js断言库API中文文档
2018/01/31 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
2018/10/10 Javascript
解决iview多表头动态更改列元素发生的错误的方法
2018/11/02 Javascript
Openlayers绘制地图标注
2020/09/28 Javascript
python简单实现获取当前时间
2016/08/27 Python
Python元组拆包和具名元组解析实例详解
2018/03/26 Python
Python Pandas找到缺失值的位置方法
2018/04/12 Python
Python面向对象编程基础实例分析
2020/01/17 Python
python删除指定列或多列单个或多个内容实例
2020/06/28 Python
利用python制作拼图小游戏的全过程
2020/12/04 Python
Python实现一个论文下载器的过程
2021/01/18 Python
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
BSTN意大利:德国街头和运动文化高品质商店
2020/12/22 全球购物
银行领导班子四风对照检查材料
2014/09/27 职场文书
离职员工给领导和同事的感谢信
2015/11/03 职场文书
2016年春季开学典礼新闻稿
2015/11/25 职场文书
Python如何使用logging为Flask增加logid
2021/03/30 Python
vue使用refs获取嵌套组件中的值过程
2022/03/31 Vue.js