原始需求:

例如有一个列表:

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多维数组拉平到一维的方法实现的更多相关文章

  1. Python中OS对目录的操作以及引用

    路径的获取对当前目录的获取1 path = os.getcwd() 2 print("获取到的当前目录是:({})".format(path))获取当前文件所在的绝对路径import ospath = os.path.realpath(__file__) print("......

  2. 剪枝决策树原理与Python实现

    机器学习经典模型决策树的实现原理,以及Python实现目录一、决策树模型 二、选择划分 2.1 信息熵和信息增益 2.2 增益率 2.3 基尼指数 三、剪枝 3.1 预剪枝 3.2 后剪枝 3.3 剪枝示例 3.4 预剪枝和后剪枝对比 四、Python实现 4.1 基尼值和基尼指数 4.2 选择划分......

  3. 利用python为PostgreSQL的表自动添加分区

    PostgreSQL引进“分区”表特性,解放了之前采用“表继承”+“触发器”来实现分区表的繁琐、低效。而添加分区,都是手动执行SQL。 演示目的:利用python来为PostgreSQL的表自动添加分区。python版本:python3+ pip3 install psycopg2 一......

  4. 用Python制作音乐海报

    前言前段时间在一个朋友那么得到的灵感,想到可以用音乐播放页面作为一张海报图片。其实接下来要讲的和海报还是有差距的,而具体实现也只是简单的图片粘贴,但是在效果上还是不错的。效果图如下,希望大家喜欢:左边是原图,右边是需要添加到中间的图,也是图的主角。其实如果直接用ps实现上面的图是非常简单的,反倒是用......

  5. python_mmdt:从0到1--实现简单恶意代码分类器(二)

    上篇文章python_mmdt:一种基于敏感哈希生成特征向量的python库(一)我们介绍了一种叫mmdt_hash(敏感哈希)生成方法,并对其中的概念做了基本介绍。本篇,我们重点谈谈mmdt_hash的分类应用场景。概述上篇文章python_mmdt:一种基于敏感哈希生成特征向量的python库(......

  6. python爬虫-数据解析(xpath)

    文章目录xpath基本概念xpath解析原理环境安装如何实例化一个etree对象:xpath(‘xpath表达式’)xpath爬取58二手房实例爬取网址完整代码效果图xpath图片解析下载实例爬取网址完整代码效果图xpath爬取全国城市名称实例爬取网址完整代码效果图xpath爬取简历模板实例爬取网址......

  7. 删除pandas中产生Unnamed:0列的操作

    我们在数据处理,往往不小心,pandas会“主动”加上行和列的名称,我现在就遇到了这个问题。这个是pandas中to_csv生成的数据各种拼接之后的最终数据(默认参数,index=True,column=True)Unnamed: 0 ip Unnamed: 0.1 ... 766 767 ......

  8. python如何实现单向链表及单向链表的反转

    链表的定义链表中的每个节点会存储相邻节点的位置信息,单链表中的每个节点只存储下一关节点的位置信息单向链表的实现class ListNode:def __init__(self, val):self.val = valself.next = None要实现单向链表只需要把几个节点关联起来就可以了,把一......

  9. Python爬虫-抓取手机APP数据

    抓取超级课程表话题数据。博文:http://my.oschina.net/jhao104/blog/606922#!/usr/local/bin/python2.7# -*- coding: utf8 -*-"""超级课程表话题抓取"""i......

  10. Python 打印自己设计的字体的实例讲解

    通过对 26 个字母的设定,设置自己要输出的字体。name = "RUNOOB"# 接收用户输入# name = input("输入你的名字: \n\n") lngth = len(name) l = "" for x in range(0......

随机推荐

  1. Perl 使用 Mail::POP3Client 发送邮件

    use Mail::POP3Client;$mail = new Mail::POP3Client("username", "password", "pop3.yourserver.com");if ($mail->Count) {p......

  2. 理解C#中的 async await

    前言一个老掉牙的话题,园子里的相关优秀文章已经有很多了,我写这篇文章完全是想以自己的思维方式来谈一谈自己的理解。(PS:文中涉及到了大量反编译源码,需要静下心来细细品味)从简单开始为了更容易理解这个问题,我们举一个简单的例子:用异步的方式在控制台上分两步输出“Hello World!”,我这边使用的......

  3. Python爬虫实现selenium处理iframe作用域问题

    项目场景:在使用selenium模块进行数据爬取时,通常会遇到爬取iframe中的内容。会因为定位的作用域问题爬取不到数据。问题描述:我们以菜鸟教程的运行实例为案例。按照正常的定位会以文本块生成xpath为/html/body/text()。这样的话根据xpath进行如下代码编写。#!/user/b......

  4. jquery表格插件Datatables使用、快速上手

    Datatables使用一、简介官网:https://datatables.net/ 中文官网:http://datatables.club/Datatables是一款jquery表格插件。它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能。操作DOM的分页,即时搜索和排序,几乎支持任......

  5. Java多线程实现简易微信发红包的方法实例

    一、首先我们先大致了解一下什么是多线程。(书上的解释)程序是一段静态的代码,它是应用软件的蓝本。进程是程序的一次动态执行过程,对应了从代码加载执行,执行到执行完毕的一个完整的过程。线程不是进程,线程是比进程更小的执行单位,一个进程在其执行过程中,可以产生多个线程形成多条执行线索,每条线索即每个线程也......

  6. Java复制(拷贝)数组的4种方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRan

    所谓复制数组,是指将一个数组中的元素在另一个数组中进行复制。本文主要介绍关于 Java 里面的数组复制(拷贝)的几种方式和用法。在 Java 中实现数组复制分别有以下 4 种方法:Arrays 类的 copyOf() 方法Arrays 类的 copyOfRange() 方法System 类的 arr......

  7. 浅析python字符串前加r、f、u、l 的区别

    先给大家介绍下Python 字符串前面加u,r,b,f的含义(字符串前缀)1、字符串前加 u例:u"我是含有中文字符组成的字符串。"作用:后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时出现乱码。2、字符串前加 r例:......

  8. OpenCV 之 图象几何变换

    二维平面中,图像的几何变换有等距、相似、仿射、投影等,如下所示: 1 图象几何变换1.1 等距变换 等距变换 (Isometric Transformation),是一种二维的刚体变换,可理解为旋转和平移的组合 $\quad \beg......

  9. php中rsort函数实例用法

    在讲到升序的数组方法后,那么对应的就会出现降序的方法。在我们正式揭晓方法之前,大家已经学习了sort函数的用法,那么对应的降序函数名称就是rsort() 。两个函数在结构语法上都非常相似,下面我们就rsort() 函数的概念、语法、返回值、降序实例带来介绍,具体使用方法如下。1.概念rsort() ......

  10. Java中获取时间戳

    Java中获取时间戳 三种方式对比**最近项目开发过程中发现了项目中获取时间戳的业务。而获取时间戳有以下三种方式,首先先声明推荐使用System类来获取时间戳,下面一起看一看三种方式。1.System.currentTimeMillis() System类中的currentTimeMillis()方......