1. 程式人生 > >Python推導式嘗試學習

Python推導式嘗試學習

列表生成式(list comprehension)是一種簡化程式碼的優美方法。根據python文件,“列表生成式提供了一種建立列表的簡潔方法。”在這篇教程裡,我將會使用一些例子來展示如果使用列表推導式。

列表推導式

列表推導式書寫形式:  

[expr for value in collection ifcondition]

1 平方列表

如果你想建立一個包含1到10的平方的列表,你可以這樣做:

squares = []
for x in range(10):
    squares.append(x**2)

這是一個簡單的例子,但是使用列表生成式可以更簡潔地建立這個列表。

squares = [x**2 for x in range(10)]

這個最簡單的列表生成式由方括號開始,方括號內部先是一個表示式,其後跟著一個for語句。列表生成式總是返回一個列表。

2 整除3的數字列表

通常,你可能這樣寫:

numbers = []
for x in range(100):
    if x % 3 == 0:
        numbers.append(x)

你可以在列表生成式裡包含一個if語句,來有條件地為列表新增項。為了建立一個包含0到100間能被3整除的數字列表,可以使用列表推導式:

numbers = [x for x in range(100
) if x % 3 == 0]

3 找出質數

這通常要使用好幾行程式碼來實現。

noprimes = []
for i in range(2, 8):
    for j in range(i*2, 50, i):
        noprimes.append(j)
primes = []
for x in range(2, 50):
    if x not in noprimes:
        primes.append(x)

不過,你可以使用兩個列表生成式來簡化程式碼。

noprimes = [j for i in range(2, 8) for j in range(i*2
, 50, i)] primes = [x for x in range(2, 50) if x not in noprimes]

第一行程式碼在一個列表生成式裡使用了多層for迴圈。第一個迴圈是外部迴圈,第二個迴圈是是內部迴圈。為了找到質數,我們首先找到一個非質數的列表。通過找出2-7的倍數來產生這個非質數列表。然後我們迴圈遍歷數字並檢視每個數字是否在非質數列表。

修正:正如reddit上的shoyer指出的,使用集合(set)來查詢noprimes(程式碼裡的屬性引數,譯者注)效率更高。由於noprimes應該只包含唯一的值,並且我們頻繁地去檢查一個值是否存在,所以我們應該使用集合。集合的使用語法和列表的使用語法類似,所以我們可以這樣使用:

noprimes = set(j for i in range(2, 8) for j in range(i*2, 50, i))
primes = [x for x in range(2, 50) if x not in noprimes]

4 巢狀列表降維

假設你有一個列表的列表(列表裡包含列表)或者一個矩陣,

matrix = [[0,1,2,3], [4,5,6,7], [8,9,10,11]]

並且你想把它降維到一個一維列表。你可以這樣做:

flattened = []
for row in matrix:
    for i in row:
        flattened.append(i)

使用列表生成式:

flattened = [i for row in matrix for i in row]

這使用了兩個for迴圈去迭代整個矩陣。外層(第一個)迴圈按行迭代,內部(第二個)迴圈對該行的每個項進行迭代。

5 模擬多個擲硬幣事件

假設需要模擬多次擲硬幣事件,其中0表示正面,1表示反面,你可以這樣編寫程式碼:

from random import random
results = []
for x in range(10):
    results.append(int(round(random())))

或者使用列表生成式使程式碼更簡潔:

from random import random
results = [int(round(random())) for x in range(10)]

這裡使用了range函式迴圈了10次。每一次我們都把random()的輸出進行四捨五入。因為random()函式返回一個0到1的浮點數,所以對輸出進行四捨五入就會返回0或者1。Round()函式返回一個浮點型資料,使用int()將其轉為整型並新增到列表裡。

6 移除句子中的母音字母

假設你有一個句子

sentence = 'Your mother was a hamster'

並且你想移除所有的母音字母。我們可以使用幾行程式碼輕易做到:

vowels = 'aeiou'
non_list = []
for l in sentence:
    if not l in vowels:
        non_list.append(l)
nonvowels = ''.join(non_list)

或者你可以使用列表生成式簡化它:

vowels = 'aeiou'
nonvowels = ''.join([l for l in sentence if not l in vowels])

這個例子使用列表生成式建立一個字母列表,字母列表的字母來自sentence句子的非母音字母。然後我們把生成的列表傳給join()函式去轉換為字串。

修正:正如reddit上的iamadogwhatisthis提出的,這個例子不需要列表生成式。使用生成器(generator)更好:

vowels = 'aeiou'
nonvowels = ''.join(l for l in sentence if not l in vowels)

注意,這裡去掉了方括號。這是因為join函式接收任意可迭代的資料,包括列表或者生成器。這個沒有方括號的語法使用了生成器。這產生(與列表生成式)同樣的結果,相對於之前把所有條目包裝成一個列表,生成器在我們遍歷時才產生相應的條目。這可以使我們不必儲存整個列表到記憶體,並且這對於處理大量資料更有效率。

7 獲取目錄裡的檔名列表

下面的程式碼將會遍歷my_dir目錄下的檔案,並在files裡追加每個以txt為字尾的檔名。

import os
files = []
for f in os.listdir('./my_dir'):
    if f.endswith('.txt'):
        files.append(f)

這同樣可以使用列表生成式簡化程式碼:

import os
files = [f for f in os.listdir('./my_dir') if f.endswith('.txt')]

或者你可以獲取一個相對路徑的列表:

import os
files = [os.path.join('./my_dir', f) for f in os.listdir('./my_dir') if f.endswith('.txt')]

感謝reddit上的rasbt提供。

8 將csv檔案讀取為字典列表

我們常常需要讀取和處理csv檔案的資料。處理csv資料的一個最有用的方法就是把它轉換為一個字典列表。

import csv
data = []
for x in csv.DictReader(open('file.csv', 'rU')):
    data.append(x)

你可以使用列表生成式快速實現:

import csv
data = [ x for x in csv.DictReader(open('file.csv', 'rU'))]

DictReader類將會自動地使用csv檔案的第一行作為字典的key屬性名。DictReader類返回一個將會遍歷csv檔案所有行的物件。這個檔案物件通過open()函式產生。我們提供了open()兩個引數–第一個是csv檔名,第二個是模式。在這例子,‘rU’有兩個意思。想往常一樣,‘r’表示以讀模式開啟檔案。‘U’表明我們將會接受通用換行符–‘n’,‘r’和‘rn’。

9.對列表中的每項元素進行立方運算(變換功能)

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [x ** 3 for x in a]

10.對列表中為偶數的元素進行立方運算(帶篩選條件的變換功能)

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [x ** 3 for x in a if x % 2 == 0]

從結果上可以看出有篩選條件的話是先篩選再變換,即先篩掉不滿足條件的元素,再進行變換運算。可以同時加多個篩選條件,如對大於5的且是偶數的元素進行立方運算,示例如下:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [x ** 3 for x in a if x % 2 == 0 if x > 5]

11.與zip結合

將a,b兩個列表中相對應得值組合起來,形成一個新列表。例如包含x座標的列表與y座標的列表形成相對應的點座標[x, y]列表。

a = [-1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
xy = [[x, y] for x, y in zip(a, b)]

12.字串(String 列表)

a= ['the %s' % d for d in xrange(10)]

13.元組列表

a=[(x,y) for x in range(12,30) for y in xrange(2,10)]

14.字典

dict([(x,y) for x in range(12) for y in xrange(8) if x>y])

字典推導式

字典推導和列表推導的使用方法是類似的,只不中括號該改成大括號。只不過產生的是集合和字典而已。

其基本格式如下:

{ key_expr: value_expr for value in collection if condition }

直接舉例說明:

1. 大小寫key合併

mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {
    k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
    for k in mcase.keys()
    if k.lower() in ['a','b']
}

2. 快速更換key和value

mcase = {'a': 10, 'b': 34}
mcase_frequency = {v: k for k, v in mcase.items()}

集合推導式

它們跟列表推導式也是類似的。 唯一的區別在於它使用大括號{}。

其基本格式如下:

{ expr for value in collection if condition }

例子:

squared = {x**2 for x in [1, 1, 2]}