將不規(guī)則的Python多維數(shù)組拉平到一維的方法實(shí)現(xiàn)
原始需求:

例如有一個(gè)列表:
l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
希望把它轉(zhuǎn)換成下面這種形式:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
其實(shí)這個(gè)非常簡(jiǎn)單,我將分享三個(gè)一行式代碼來(lái)解決這個(gè)問(wèn)題。
但如果是下面這種不規(guī)則的多維列表:
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]
又該怎么實(shí)現(xiàn)呢?
文末將演示通過(guò)遞歸或棧來(lái)實(shí)現(xiàn)深度優(yōu)先遍歷策略從而解決這個(gè)問(wèn)題。
使用numpy拉平數(shù)組
import numpy as np np.array(l).flatten().tolist()
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
使用python拉平數(shù)組
使用numpy數(shù)組拉平數(shù)組,其實(shí)很受限,一旦列表內(nèi)部每個(gè)元素的長(zhǎng)度不一致,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
結(jié)果:
[[1, 2, 3], [4, 5], [6, 7], [8, 9, 10, 11]]
這時(shí)我們可以通過(guò)python的itertools來(lái)實(shí)現(xiàn)高效的操作:
import itertools list(itertools.chain(*l))
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
當(dāng)然還有一種更高級(jí)的操作方法是直接使用sum函數(shù):
sum(l, [])
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
你可能一臉懵逼,為什么sum函數(shù)可以實(shí)現(xiàn)列表的拉平?下面我翻譯一下,這段代碼實(shí)際做了什么:
result = [] for i in l: result += i result
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
將不規(guī)則多維數(shù)組拉平到1維
例如,對(duì)于下面這個(gè)復(fù)雜的列表:
l = [[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]] l
結(jié)果:
[[1, 2], [3, 4], [5, [6, 7, [8, 9]]], 10, [11, [12, 13, [14, 15, [16]]]]]
這樣的列表,對(duì)于上面的方法來(lái)說(shuō)已經(jīng)都不好使了,這個(gè)時(shí)候怎么辦呢?
當(dāng)然對(duì)于這種長(zhǎng)度不長(zhǎng)的列表,我們可以玩點(diǎn)小技巧:
list_str = str(l).replace("[", "").replace("]", "")
eval(f"[{list_str}]")
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
當(dāng)然,使用正則替換更佳:
import re
eval(re.sub("(?!^)\[|\](?!$)", "", str(l)))
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
原理就是先將這個(gè)列表轉(zhuǎn)成普通的字符串,再將所有的[]字符都去掉,再轉(zhuǎn)成單維列表的字符串形式之后,用eval函數(shù)進(jìn)行解析。但這種方式在列表足夠長(zhǎng)的時(shí)候顯然是不合適的,會(huì)出現(xiàn)效率低下的問(wèn)題。
深度優(yōu)先遍歷策略拉平多維數(shù)組
下面我介紹一個(gè)正常的解決這個(gè)問(wèn)題的辦法,那就是使用深度優(yōu)先遍歷策略來(lái)解決這個(gè)問(wèn)題,當(dāng)然如果你對(duì)拉平的結(jié)果沒(méi)有順序的要求還可以使用廣度優(yōu)先遍歷的策略。
深度優(yōu)先遍歷策略,最簡(jiǎn)單直接的思路是使用遞歸來(lái)實(shí)現(xiàn):
def flatten(items, result=[]):
for item in items:
if isinstance(item, list):
flatten(item, result)
else:
result.append(item)
result = []
flatten(l, result)
result
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
雖然遞歸可能出現(xiàn)調(diào)用棧過(guò)多導(dǎo)致性能下降或程序掛掉,但Python可以借助生成器讓遞歸調(diào)用變成普通調(diào)用:
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
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
而如果我們想不使用遞歸或生成器類遞歸,可以直接借助一個(gè)棧來(lái)實(shí)現(xiàn)。
為了保證結(jié)果是原有的順序,我們把左端作為棧頂,而數(shù)組不適合刪除左端的數(shù)據(jù),所以可以使用deque來(lái)作為棧。
首先,我們需要將原列表轉(zhuǎn)換為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
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
如果我們將原列表作為一個(gè)右端為棧頂?shù)臈#梢酝ㄟ^(guò)向結(jié)果左端插入數(shù)據(jù)來(lái)保持原有的順序:
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
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
小結(jié)
想不到小小的列表拉平還有這么多學(xué)問(wèn),希望今天的分享能夠?qū)ψ屇銓W(xué)有所獲。
到此這篇關(guān)于將不規(guī)則的Python多維數(shù)組拉平到一維的方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python多維數(shù)組拉平到一維內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python如何使用sqlalchemy實(shí)現(xiàn)動(dòng)態(tài)sql
SQLAlchemy是一個(gè)功能強(qiáng)大的ORM(對(duì)象關(guān)系映射)工具,它提供了多種方式來(lái)生成SQL查詢,包括動(dòng)態(tài)SQL,下面我們就來(lái)學(xué)習(xí)一下具體的使用方法吧2024-12-12
python xmind 包使用詳解(其中解決導(dǎo)出的xmind文件 xmind8可以打開 xmind2020及之后版本打
xmind8 可以打開xmind2020 報(bào)錯(cuò),如何解決這個(gè)問(wèn)題呢?下面小編給大家?guī)?lái)了python xmind 包使用(其中解決導(dǎo)出的xmind文件 xmind8可以打開 xmind2020及之后版本打開報(bào)錯(cuò)問(wèn)題),感興趣的朋友一起看看吧2021-10-10
python數(shù)據(jù)處理實(shí)戰(zhàn)(必看篇)
下面小編就為大家?guī)?lái)一篇python數(shù)據(jù)處理實(shí)戰(zhàn)(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
python簡(jiǎn)單實(shí)現(xiàn)AES加密和解密
這篇文章主要為大家詳細(xì)介紹了python簡(jiǎn)單實(shí)現(xiàn)AES加密和解密,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
Python通過(guò)Django實(shí)現(xiàn)用戶注冊(cè)和郵箱驗(yàn)證功能代碼
這篇文章主要介紹了Python通過(guò)Django實(shí)現(xiàn)用戶注冊(cè)和郵箱驗(yàn)證功能代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
python檢測(cè)服務(wù)器端口代碼實(shí)例
這篇文章主要介紹了python檢測(cè)服務(wù)器端口代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Django關(guān)于admin的使用技巧和知識(shí)點(diǎn)
在本篇文章里小編給大家整理的是關(guān)于Django的admin簡(jiǎn)單使用的相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的朋友們可以跟著學(xué)習(xí)下。2020-02-02

