Python 陣列 與 List comprehension 列表推導式

Python 陣列 與 List comprehension 列表推導式

更新於 發佈於 閱讀時間約 6 分鐘

Array可以說是各種語言除了基本型別之外,最常用的資料型別與容器之一了。

Array 這種連續格子狀的資料結構,在Python要怎麼表達呢?


建立一個空的陣列

最簡單也最直接的寫法就是

array = [] # Python list [] 就對應到大家熟知的array 陣列型態的資料結構

或者

array = list() # 相當於呼叫list()的建構子

這兩個語法都相當於建立一個空的陣列。

印出來,可以很清楚看到結果,就是一個[],裡面什麼東西都沒有。

raw-image

增加元素

在尾巴加入新元素

array.append( x ) # 在尾巴插入一個新的元素。

用起來就好像C++ vector 的 push_back(x) ,會在尾端新增一筆資料,內容為x

raw-image


在指定位置插入新元素

# 在pos位置,插入element
# pos 從0開始起算,0是最前面的位置
array.insert(pos, element)

觀念上有點像C++ vector的insert,差別在於C++接收的參數是iterator

除非有特殊需求,一般日常應用不建議這麼用,因為複雜度是O(n)線性等級的。

run-time的時間成本很高。

raw-image

讀取指定陣列位址的元素

和其他主流高階語言相同,都支援array[index]的陣列元素存取語法。

index 同樣是從0開始起算,0是開頭的索引編號

# 印出array[0]
print( array[0])

index = 1
# 印出array[index]​
print( array[index])
raw-image

刪除元素

刪除並且回傳尾巴最後一個元素

array.pop()

如果把array 當成stack來用,

那麼array.append(x) 就對應到 stack 的 push(x) 操作

array.pop() 就對應到 stack 的 pop()操作

raw-image


刪除並且回傳指定位置的陣列元素

# 刪除並且回傳array[pos]
# pos 從0開始起算,0是最前面的位置
array.pop( pos )

觀念上有點像C++ vector的erase,差別在於C++接收的參數是iterator

除非有特殊需求,一般日常應用不建議這麼用,因為複雜度是O(n)線性等級的。

run-time的時間成本很高。

raw-image

建立帶有初始值的陣列

如何有規律的生成元素,或者生成一整塊帶有初始值的陣列?

傳統高階語言寫法: 使用迴圈

如果我們要建立一個長度為10的陣列,裡面初始值都是0。

可以這樣寫

array = []

for i in range(10):
array.append(0)

print(array)

得到的輸出就是

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]


另一個例子是,如果建立一個長度為10的陣列,裡面初始值就是流水號0~9。

可以這樣寫

array = []

for i in range(10):
array.append(i)

print(array)

得到的輸出就是

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

List comprehension 列表推導式

Python提供一個更簡潔也更彈性的語法List comprehension,
中文稱之為列表推導式(或 列表生程式),
可以在把初始化的常數、運算式或函式直接放在[]裡面。

語法可以這樣表達

[ 初始值 for 索引變數 in range( ... ) ]

或者

[ 函式計算的結果 for 索引變數 in range( ... ) ]


如果我們要建立一個長度為10的陣列,裡面初始值都是0。

用List comprehension來寫,就變成這樣

array =[ 0 for i in range(10)]
print(array)

得到的輸出同樣是

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]


如果我們要建立一個長度為10的陣列,裡面初始值是流水號0~9。

用List comprehension來寫,就變成這樣

array =[ i for i in range(10)]
print(array)

得到的輸出就是

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


如同剛剛語法的介紹,給予函數計算結果或者等價的lambda expression 也是可以的。

例如,想要根據奇數、偶數輸出提示字串,可以這樣寫

def judge(x):
if x % 2 == 0:
return f"{x} is Even"
else:
return f"{x} is Odd"

array =[ judge(i) for i in range(6) ]
print(array)

得到的輸出就是

['0 is Even', '1 is Odd', '2 is Even', '3 is Odd', '4 is Even', '5 is Odd']


例如,想要得到前10個完全平方數,可以這樣寫

array =[ i**2 for i in range(1, 11, 1) ]
print(array)

得到的輸出就是

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]


例如,想要判斷流水號i 是不是3的倍數,可以這樣寫

array =[ (i % 3 ==0) for i in range(6) ]
print(array)

得到的輸出就是

[True, False, False, True, False, False]


另外,由於支援range迭代器(起點, 終點, 步伐)的語法,

所以控制起點、終點迭代區間也是可行的。


註: Python range的區間是包含起點,不包含終點,請特別留意


例如,想要輸出100到120之間的偶數陣列,可以這樣寫

array =[ i for i in range(100, 122, 2) ]
print(array)

得到的輸出就是

[100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120]

Reference:

[1] 5. Data Structures — Python 3.12.4 documentation

avatar-img
小松鼠的演算法樂園
95會員
426內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言
avatar-img
留言分享你的想法!
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。