問題
你有一個數(shù)據(jù)序列,想利用一些規(guī)則從中提取出需要的值或者是縮短序列
解決方案
最簡單的過濾序列元素的方法就是使用列表推導。比如:
1
2
3
4
5
6
|
>>> mylist = [ 1 , 4 , - 5 , 10 , - 7 , 2 , 3 , - 1 ] >>> [n for n in mylist if n > 0 ] [ 1 , 4 , 10 , 2 , 3 ] >>> [n for n in mylist if n < 0 ] [ - 5 , - 7 , - 1 ] >>> |
使用列表推導的一個潛在缺陷就是如果輸入非常大的時候會產(chǎn)生一個非常大的結果集,占用大量內(nèi)存。 如果你對內(nèi)存比較敏感,那么你可以使用生成器表達式迭代產(chǎn)生過濾的元素。比如:
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> pos = (n for n in mylist if n > 0 ) >>> pos <generator object <genexpr> at 0x1006a0eb0 > >>> for x in pos: ... print (x) ... 1 4 10 2 3 >>> |
有時候,過濾規(guī)則比較復雜,不能簡單的在列表推導或者生成器表達式中表達出來。 比如,假設過濾的時候需要處理一些異常或者其他復雜情況。這時候你可以將過濾代碼放到一個函數(shù)中, 然后使用內(nèi)建的 filter() 函數(shù)。示例如下:
1
2
3
4
5
6
7
8
9
10
|
values = [ '1' , '2' , '-3' , '-' , '4' , 'N/A' , '5' ] def is_int(val): try : x = int (val) return True except ValueError: return False ivals = list ( filter (is_int, values)) print (ivals) # Outputs ['1', '2', '-3', '4', '5'] |
filter() 函數(shù)創(chuàng)建了一個迭代器,因此如果你想得到一個列表的話,就得像示例那樣使用 list() 去轉(zhuǎn)換。
討論
列表推導和生成器表達式通常情況下是過濾數(shù)據(jù)最簡單的方式。 其實它們還能在過濾的時候轉(zhuǎn)換數(shù)據(jù)。比如:
1
2
3
4
5
|
>>> mylist = [ 1 , 4 , - 5 , 10 , - 7 , 2 , 3 , - 1 ] >>> import math >>> [math.sqrt(n) for n in mylist if n > 0 ] [ 1.0 , 2.0 , 3.1622776601683795 , 1.4142135623730951 , 1.7320508075688772 ] >>> |
過濾操作的一個變種就是將不符合條件的值用新的值代替,而不是丟棄它們。 比如,在一列數(shù)據(jù)中你可能不僅想找到正數(shù),而且還想將不是正數(shù)的數(shù)替換成指定的數(shù)。 通過將過濾條件放到條件表達式中去,可以很容易的解決這個問題,就像這樣:
1
2
3
4
5
6
7
|
>>> clip_neg = [n if n > 0 else 0 for n in mylist] >>> clip_neg [ 1 , 4 , 0 , 10 , 0 , 2 , 3 , 0 ] >>> clip_pos = [n if n < 0 else 0 for n in mylist] >>> clip_pos [ 0 , 0 , - 5 , 0 , - 7 , 0 , 0 , - 1 ] >>> |
另外一個值得關注的過濾工具就是 itertools.compress()
, 它以一個 iterable
對象和一個相對應的 Boolean
選擇器序列作為輸入?yún)?shù)。 然后輸出 iterable
對象中對應選擇器為 True
的元素。 當你需要用另外一個相關聯(lián)的序列來過濾某個序列的時候,這個函數(shù)是非常有用的。 比如,假如現(xiàn)在你有下面兩列數(shù)據(jù):
1
2
3
4
5
6
7
8
9
10
11
|
addresses = [ '5412 N CLARK' , '5148 N CLARK' , '5800 E 58TH' , '2122 N CLARK' , '5645 N RAVENSWOOD' , '1060 W ADDISON' , '4801 N BROADWAY' , '1039 W GRANVILLE' , ] counts = [ 0 , 3 , 10 , 4 , 1 , 7 , 6 , 1 ] |
現(xiàn)在你想將那些對應 count
值大于5的地址全部輸出,那么你可以這樣做:
1
2
3
4
5
6
7
|
>>> from itertools import compress >>> more5 = [n > 5 for n in counts] >>> more5 [ False , False , True , False , False , True , True , False ] >>> list (compress(addresses, more5)) [ '5800 E 58TH' , '1060 W ADDISON' , '4801 N BROADWAY' ] >>> |
這里的關鍵點在于先創(chuàng)建一個 Boolean
序列,指示哪些元素符合條件。 然后 compress()
函數(shù)根據(jù)這個序列去選擇輸出對應位置為 True
的元素。
和 filter()
函數(shù)類似, compress()
也是返回的一個迭代器。因此,如果你需要得到一個列表, 那么你需要使用 list()
來將結果轉(zhuǎn)換為列表類型。
以上就是Python過濾序列元素的方法的詳細內(nèi)容,更多關于Python過濾序列元素的資料請關注服務器之家其它相關文章!
原文鏈接:https://python3-cookbook.readthedocs.io/zh_CN/latest/c01/p16_filter_sequence_elements.html