将不规则的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中的引用和拷贝浅析
Nov 22 Python
解决python3 urllib中urlopen报错的问题
Mar 25 Python
django开发教程之利用缓存文件进行页面缓存的方法
Nov 10 Python
分分钟入门python语言
Mar 20 Python
python框架中flask知识点总结
Aug 17 Python
Python把对应格式的csv文件转换成字典类型存储脚本的方法
Feb 12 Python
使用Python代码实现Linux中的ls遍历目录命令的实例代码
Sep 07 Python
Python中关于浮点数的冷知识
Sep 22 Python
pyinstaller打包成无控制台程序时运行出错(与popen冲突的解决方法)
Apr 15 Python
浅谈pycharm导入pandas包遇到的问题及解决
Jun 01 Python
python3中calendar返回某一时间点实例讲解
Nov 18 Python
使用Python+Appuim 清理微信的方法
Jan 26 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
苏联队长,苏联超人蝙蝠侠,这些登场的“山寨”英雄真的很严肃
2020/04/09 欧美动漫
利用PHP生成静态HTML文档的原理
2012/10/29 PHP
php实现memcache缓存示例讲解
2013/12/04 PHP
完整删除ecshop中获取店铺信息的API
2014/12/24 PHP
php获取当月最后一天函数分享
2015/02/02 PHP
PHP 网站修改默认访问文件的nginx配置
2017/05/27 PHP
浅谈Yii乐观锁的使用及原理
2017/07/25 PHP
PHP实现的二分查找算法实例分析
2017/12/19 PHP
农历与西历对照
2006/09/06 Javascript
在IE浏览器中resize事件执行多次的解决方法
2011/07/12 Javascript
Javascript代码在页面加载时的执行顺序介绍
2013/05/03 Javascript
浅析JQuery获取和设置Select选项的常用方法总结
2013/07/04 Javascript
jQuery中delegate与on的用法与区别示例介绍
2013/12/20 Javascript
JavaScript声明变量名的语法规则
2015/07/10 Javascript
分分钟玩转Vue.js组件
2016/10/25 Javascript
JS实现点击拉拽轮播图pc端移动端适配
2018/09/05 Javascript
JavaScript原型对象原理与应用分析
2018/12/27 Javascript
JavaScript变量提升和严格模式实例分析
2019/01/27 Javascript
JS简单表单验证功能完整示例
2020/01/26 Javascript
javascript实现时钟动画
2020/12/03 Javascript
Python数组条件过滤filter函数使用示例
2014/07/22 Python
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
Python3读取UTF-8文件及统计文件行数的方法
2015/05/22 Python
python实现机械分词之逆向最大匹配算法代码示例
2017/12/13 Python
pygame游戏之旅 添加游戏界面按键图形
2018/11/20 Python
将python包发布到PyPI和制作whl文件方式
2019/12/25 Python
django 数据库返回queryset实现封装为字典
2020/05/19 Python
HTML5新增元素如何兼容旧浏览器有哪些方法
2014/05/09 HTML / CSS
JD Sports意大利:英国篮球和运动时尚的领导者
2017/10/29 全球购物
日期和时间问题
2015/01/04 面试题
销售经理工作失职检讨书
2014/10/24 职场文书
2015年文明创建工作总结
2015/04/30 职场文书
冲出亚马逊观后感
2015/06/03 职场文书
vue实现无缝轮播效果(跑马灯)
2021/05/14 Vue.js
pandas中对文本类型数据的处理小结
2021/11/01 Python
关于MybatisPlus配置双数据库驱动连接数据库问题
2022/01/22 Java/Android