将不规则的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 相关文章推荐
使用Pyrex来扩展和加速Python程序的教程
Apr 13 Python
python3抓取中文网页的方法
Jul 28 Python
十条建议帮你提高Python编程效率
Feb 16 Python
浅析Python基础-流程控制
Mar 18 Python
Python实现TCP/IP协议下的端口转发及重定向示例
Jun 14 Python
TensorFlow安装及jupyter notebook配置方法
Sep 08 Python
浅谈python迭代器
Nov 08 Python
python Opencv将图片转为字符画
Feb 19 Python
Python结合ImageMagick实现多张图片合并为一个pdf文件的方法
Apr 24 Python
pandas中去除指定字符的实例
May 18 Python
通过实例解析python创建进程常用方法
Jun 19 Python
Python 必须了解的5种高级特征
Sep 10 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
Ajax+PHP 边学边练 之二 实例
2009/11/24 PHP
PHP模板引擎Smarty内建函数详解
2016/04/11 PHP
JS模拟面向对象全解(二、类型与赋值)
2011/07/13 Javascript
Uglifyjs(JS代码优化工具)入门 安装使用
2020/04/13 Javascript
JS弹出窗口代码大全(详细整理)
2012/12/21 Javascript
jquery动态加载js三种方法实例
2013/08/03 Javascript
js为空或不是对象问题的快速解决方法
2013/12/11 Javascript
纯javascript响应式树形菜单效果
2015/11/10 Javascript
js实现不重复导入的方法
2016/03/02 Javascript
JS仿hao123导航页面图片轮播效果
2016/09/01 Javascript
AngularJS实现的回到顶部指令功能实例
2017/05/17 Javascript
Javasript设计模式之链式调用详解
2018/04/26 Javascript
express 项目分层实践详解
2018/12/10 Javascript
JavaScript格式化json和xml的方法示例
2019/01/22 Javascript
JS双向链表实现与使用方法示例(增加一个previous属性实现)
2019/01/31 Javascript
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
2019/04/04 Javascript
Angular2使用SVG自定义图表(条形图、折线图)组件示例
2019/05/10 Javascript
Smartour 让网页导览变得更简单(推荐)
2019/07/19 Javascript
微信小程序自定义组件components(代码详解)
2019/10/21 Javascript
jQuery实现简单全选框
2020/09/13 jQuery
[01:29]2014DOTA2展望TI 剑指西雅图DK战队专访
2014/06/30 DOTA
[01:19]DOTA2城市挑战赛报名开始 开启你的城市传奇
2018/03/23 DOTA
Linux(Redhat)安装python3.6虚拟环境(推荐)
2018/05/05 Python
Python根据已知邻接矩阵绘制无向图操作示例
2018/06/23 Python
对python3 一组数值的归一化处理方法详解
2018/07/11 Python
Python使用pyshp库读取shapefile信息的方法
2018/12/29 Python
Python骚操作之动态定义函数
2019/03/26 Python
详解用python写一个抽奖程序
2019/05/10 Python
使用Python来做一个屏幕录制工具的操作代码
2020/01/18 Python
浅谈keras中的目标函数和优化函数MSE用法
2020/06/10 Python
Python基于network模块制作电影人物关系图
2020/06/19 Python
如何设置PyCharm中的Python代码模版(推荐)
2020/11/20 Python
HTML5 Canvas基本线条绘制的实例教程
2016/03/17 HTML / CSS
Python中如何定义一个函数
2016/09/06 面试题
2014年乡镇安全生产工作总结
2014/12/02 职场文书
离婚财产分割协议书
2015/08/11 职场文书