将不规则的Python多维数组拉平到一维的方法实现
作者:小小明(代码实体) 发布时间:2023-11-05 19:47:15
原始需求:
例如有一个列表:
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]
小结
想不到小小的列表拉平还有这么多学问,希望今天的分享能够对让你学有所获。
来源:https://blog.csdn.net/as604049322/article/details/112387064
猜你喜欢
- 有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授权表。比较好的方法是使用GRANT语句,因为他们是更简明并且好像错
- 今天在调试项目的时候出现下面的错误信息:SoapFaultlooks like we got no XML document (D:\php
- 前言在Python中可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)这几个概念是经常用到的,初学时对这几
- 前一段时间,一个流行的东方系列mv 《bad apple》 带来一股奇怪的风潮: 各种技术狂人纷纷把这段mv在一些匪夷
- 在XHTML中定义ID、CLASS都用得上,主要是方面CSS定义样式时能一眼看穿。所以,CSS命名仅作参考。(1)页面结构类容器: cont
- 一条语句搞定数据库分页select top 10 b.* from (select&nbs
- 1、确认框架中安装了第三方alibabacoud控件实现代码如下上传过程中遇到任务问题,可以进行留言<?php namespace A
- 编写程序的时候,经常要处理字符串,最基本就是字符串的查找,在php检测字符串中是否包含指定字符串可以使用正则,如果你对正则不了解,那么有几个
- 在没步入正轨之前,先给大家介绍JavaScript 特殊字符你可以在 JavaScript 中使用反斜杠来向文本字符串添加特殊字符。插入特殊
- 关于采集-防采集的我想大家都很清楚。这个就不多说,采集最终还是从页面源代码入手,所以只要没有规律想采集就难!由于一天自己在策划某个网站的时候
- 这个话题是应腾讯ISD同仁之邀在WebReBuild三周年交流会上做的主题分享。由于临场等原因有些问题当时没有讲明白,回来后按原有思路形成了
- 他们是如何不让我的Teleport和Webzip工作的?你也可以做得到哦: <%dim UserAgentUser
- 加上设置字符编码的方法:response.setHeader("charset","gb2312")
- RegExp就是建立正则的对像。如:Set regEx = New RegExp regE
- python将字典内容写入json文件的方法:我们可以先使用json.dumps()函数将字典转换为字符串;然后再将内容写入json即可。j
- 一个更易读的网站意味着网站使用性的改良以及提供愉悦的阅读体验。我们希望浏览者们能或者这些好处不是吗?这篇文章我们将介绍5个简单的方法让你能提
- 1. 相对与比较老的环境,建议使用第二个 set dbconnection=Server.CREATEOBJECT("ADODB.
- 平面设计 常用尺寸 三折页广告 标准尺寸: (A4)210mm x 285mm普通宣传册 标准尺寸: (A4)210mm x 285mm文件
- 数据库是什么 在学习ACCESS之前,我们先了解一下什么是“数据库”。我们举个例子来说明这个问题:每个人都有很多亲戚和朋友,为了保持与他们的
- 随着因特网的发展,在网络环境中,数据库应用渐渐向操作简单、功能实用的方向发展。本文介绍如何利用ASP技术实现对数据库进行在线维护的方法,并给