Python常用內置函數filter、map、reduce、apply、zip

Python將復雜的數據結構隱藏在內置函數中,用C語言來實現,所以只要寫出自己的業務邏輯,Python會自動得出你想要的結果。

內置函數主要有:filter、map、reduce、apply,結合匿名函數lambda、列表解析一起使用,功能更加強大。

如果對于大數據Hadoop和Spark感興趣的話,最好學會這些內置函數的用法。因為Hadoop的分布式計算框架采用的是MapReduce模型,該模型的核心就是Map函數和Reduce函數。
Spark的核心建立在RDD上,RDD的轉換API和動作API也包括filter、map和reduce,并且常與lambda結合使用。

使用內置函數的好處是:

  1. 使用內置函數,比普通的Python實現,速度要快一倍左右。
  2. 代碼簡潔。

1 lambda表達式

lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯。lambda表達式是起到一個函數速寫的作用,允許在代碼內嵌入一個函數的定義。

如果你不想在程序中對一個函數使用兩次,你也許會想用lambda表達式,它們和普通的函數完全一樣。

原型:

lambda  參數 : 操作(參數)

參數就是函數中所謂的入參,操作就是返回的計算結果,相當于return語句。

在數據分析的過程中,常常需要使用apply和lambda函數。比如:根據逾期天數來給數據打標簽,如果逾期天數大于30天,則為逾期。

data['target'] = data['逾期天數'].apply(lambda x: 1 if x>30 else 0)

例1. 定義一個lambda表達式,求三個數的和。

>>> f=lambda x,y,z:x+y+x
>>> f(1,2,3)
4
>>> f=lambda x,y,z:x+y+z
>>> f(1,2,3)
6

例2. 用lambda表達式求n的階乘。

>>> n=5
>>> reduce(lambda x,y:x*y,range(1,n+1))
120

例3. lambda表達式也可以用在def函數中。

>>> def action(x):
        return lambda y:x+y
>>> a=action(2)
>>> a(22)
24

這里定義了一個action函數,返回了一個lambda表達式。其中lambda表達式獲取到了上層def作用域的變量名x的值。

a是action函數的返回值,a(22),即是調用了action返回的lambda表達式。這里也可以把def直接寫成lambda形式。如下:

>>> b=lambda x:lambda y:x+y
>>> a=b(3)
>>> a(2)
5
>>>(b(2))(2)
4

2 filter

>>> help(filter)
Help on built-in function filter in module __builtin__:

filter(...) 
    filter(function or None, sequence) -> list, tuple, or string

Return those items of sequence for which function(item) is true. 
If function is None, return the items that are true. If sequence is a tuple or string,
return the same type, else return a list.

用途:

用于過濾與函數func()不匹配的值, 類似于SQL中select value != 'a'。相當于一個迭代器,調用一個布爾函數func來迭代seq中的每個元素,返回一個是bool_seq返回為True的序列。

filter()把傳入的函數依次作用于每個元素,然后根據返回值是True還是False決定保留還是丟棄該元素。

第一個參數:函數或None。
第二個參數:序列。

說明:

  • 如果第一個參數為function,那么返回條件為真的序列(列表,元組或字符串)。
  • 如果第一個參數為None的話,那么返回序列中所有為True的項目。

顧名思義,filter過濾列表中的元素,并且返回一個由所有符合要求的元素所構成的列表,符合要求即函數映射到該元素時返回值為True。這里是一個簡短的例子:

number_list = range(-5, 5)
less_than_zero = filter(lambda x: x < 0, number_list)
print(list(less_than_zero))

# 輸出為: 
[-5, -4, -3, -2, -1]

這個filter類似于一個for循環,但它是一個內置函數,并且更快。大部分情況下推導式的可讀性更好。

例1. 要過濾掉所有值為False的列表。

print filter(None,[-2,0,2,'',{},()])    # 輸出[-2,2],其余的都為False

例2. 過濾某個字母。

>>> filter(lambda x: x !='a','abcd')
'bcd'

例3. 過濾字母以B開頭的人名。

>>> names = ['Alice','Bob','Smith','David','Barbana']
>>> filter(lambda x: x.startswith('B'),names)
['Bob', 'Barbana']

例4. 過濾fib列表中的奇數,偶數項。

>>> fib = [0,1,1,2,3,5,8,13,21]
>>> filter(lambda x: x%2,fib)   # 實際上等同于x%2==1的項才過濾
[1, 1, 3, 5, 13, 21]
>>> filter(lambda x: x%2==0,fib)
[0, 2, 8]

例5. 將2-20間所有質數列出來。

>>> filter(lambda x: not [x for i in range(2,x) if x%i==0],range(2,20))
[2, 3, 5, 7, 11, 13, 17, 19]

例6. 過濾人名為空的序列。

>>> names = ['Alice','Jerry','Sherry','Bob','Tom','']
>>> filter(None,names)
['Alice', 'Jerry', 'Sherry', 'Bob', 'Tom']

例7. 過濾某目錄下所有以test.py結尾的文件。

import os,re                                   # 需要的模塊 
files = os.listdir(r'D:\python')               # 列出需要查找的目錄的所有文件 
test = re.compile('test.py$',re.IGNORECASE)    # re.IGNORECASE忽略大小寫 
print filter(test.search,files)                # 過濾所有滿足條件的文件 
>>> 
['1test.py', 'test.py']

例8. 過濾所有子列表中,單詞為'Python'的。

def filter_word(word): 
    try: 
        return word != 'Python' 
    except ValueError: 
        return False 

words = [['Perl','Python','Shell'],['Java','C/C++'],['VB','Dephi']] 
print [filter(filter_word,word) for word in words]   # 用了列表解析的方法

filter的邏輯實現:

def filter(func,seq):
    f_seq = []                    # 建一個空序列,用于存儲過濾后的元素 
    for item in seq:              # 對序列中的每個元素進行迭代 
        if func(item):            # 如果為真的話 
            f_seq.append(item)    # 滿足條件者,則加入 
    return f_seq                  # 返回過濾后的元素

>>> print filter(lambda x: x>0,[-2,0,2])   # 對匿名函數進行過濾,返回正值[2]

3 map

>>> help(map)
Help on built-in function map in module __builtin__:

map(...) 
    map(function, sequence[, sequence, ...]) -> list

Return a list of the results of applying the function to the items ofthe argument sequence(s). 
If more than one sequence is given, the function is called with an argument list consisting
of the corresponding item of each sequence, substituting None for missing values when not all
sequences have the same length. If the function is None, return a list of the items of the
 sequence (or a list of tuples if more than one sequence).

用途:

對一個及多個序列執行同一個操作,返回一個列表。

說明:

  • 返回一個列表,該列表是參數func對seq1,seq2處理的結果集。
  • 可以有多個序列,如果函數為None的話,返回一個序列的列表。

map規范:

map(function_to_apply, list_of_inputs)

大多數時候,我們要把列表中所有元素一個個地傳遞給一個函數,并收集輸出。比方說:

items = [1, 2, 3, 4, 5]
squared = []
for i in items:
    squared.append(i**2)

Map可以讓我們用一種簡單而漂亮得多的方式來實現。就是這樣:

items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))

大多數時候,我們使用匿名函數(lambda)來配合map, 所以我在上面也是這么做的。 不僅用于一列表的輸入, 我們甚至可以用于一列表的函數!

def multiply(x):
    return (x*x)
def add(x):
    return (x+x)

funcs = [multiply, add]
for i in range(5):
    value = map(lambda x: x(i), funcs)
    print(list(value))

# 輸出為:
[0, 0]
[1, 2]
[4, 4]
[9, 6]
[16, 8]

例1. 常規用法。

>>> map(lambda x: x+1,[1,2,3,4])
[2, 3, 4, 5]

>>> map(lambda x,y: x+y,[1,2,3,4],(10,20,30,40)) 
[11, 22, 33, 44]

#第一個序列中的第五個元素存在,但在第二個序列中不存在,所以y為False,所以執行5+10 
>>> map(lambda x,y: x+y if y else x+10,[1,2,3,4,5],(1,2,3,4)) 
[2, 4, 6, 8, 15]

>>> map(None,[1,2,3,4,5],(1,2)) #如果是None的話,以None來補齊短序列造成的空缺 
[(1, 1), (2, 2), (3, None), (4, None), (5, None)]

>>> names = ['Alice','Jerry','Bob','Barbar'] 
>>> map(len,names) #求列表中每個元素的長度 
[5, 5, 3, 6]

>>> m = [1,4,7] 
>>> n = [2,5,8] 
>>> map(None,m,n)
[(1, 2), (4, 5), (7, 8)]

>>> import operator #比較兩個列表中元素大小 
>>> a = [1,2,3]
>>> b = [0,4,9] 
>>> map(operator.gt,a,b) 
[True, False, False]

例2. 求0-5之間數,[本身,平方,立方],如:元素2,則返回:[2,4,8]。

def func1(x): 
   return x           # 返回自身 
def func2(x): 
   return x ** 2      # 返回平方 
def func3(x): 
   return x ** 3      # 返回立方

funcs = [func1,func2,func3]   # 函數列表 

for i in range(5):        # 遍歷列表
   print map(lambda func: func(i),funcs)  # 對其中每個元素執行func1(i),func2(i),func3(i)操作

例3. 實現下面的邏輯結構。

1.0 [1,2,3,4,5]
2.0 [1,2,3,4,5]
....

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]

def test(foo): 
    print foo,bars

print map(test,foos)

例4. 結合map和filter,求0-10之間偶數的平方,匯合成列表。

>>> map(lambda x:x**2, filter(lambda x: x%2==0,range(10))) 
[0, 4, 16, 36, 64]

map的邏輯實現:

def map(func,seq): 
    map_seq = []                          # 建空序列 
    for item in seq:                      # 對序列中每個元素進行處理 
        map_seq.append(func(item))        # 往空序列中添加func處理過的元素 
    return map_seq                        # 返回最后的列表

print map(lambda x: x * 2,[1,2,3,4])      # [2,4,6,8]

4 reduce

>>> help(reduce)
Help on built-in function reduce in module __builtin__:

reduce(...) 
    reduce(function, sequence[, initial]) -> value

Apply a function of two arguments cumulatively to the items of a sequence, from left to right, 
so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 
calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence
in the calculation, and serves as a default when the sequence is empty.

用途:

func為二元函數,將func作用于seq序列的元素,每次攜帶一對(先前的結果以及下一個序列的元素),連續的將現有的結果和下一個值作用在獲得的隨后結果上,最后減少我們的序列為一個單一的返回值:如果初始值init給定,第一個比較會是init和第一個序列元素而不是序列的頭兩個元素。

說明:

在Python3.0里面必須導入functools模塊,from functools import reduce。reduce返回的必然是一個值,可以有初始值。

當需要對一個列表進行一些計算并返回結果時,reduce是個非常有用的函數。

舉個例子,當你需要計算一個整數列表的乘積時,通常在python中你可能會使用基本的for循環來完成這個任務。
現在我們來試試reduce:

from functools import reduce
product = reduce((lambda x, y: x * y), [1, 2, 3, 4])
# 輸出為:
24

例子:

 >>> reduce(lambda x,y: x+y, [47,11,42,13])
 113

其實現過程如下圖所示:

其實現過程等同下面的:

>>> import operator 
>>> reduce(operator.add,[47,11,42,13]) 
113

注意:

  1. func()函數不能為None,否則報錯。
>>> reduce(None,[1,2,3,4])
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
  1. func(x,y)只能有兩個參數,否則報錯。
>>> reduce(lambda x,y,z: x+y+z, [1,2,3,4],9)
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 3 arguments (2 given)

reduce的邏輯實現:

def reduce(func,seq,init=None):
    l_seq = list(seq)    
    if init is None:  
        res = l_seq.pop(0) 
    else: 
        res = init 
    for item in l_seq: 
        res = func(res,item)     # func(res,item)作為結果集傳給res 
    return res                   # 返回結果集

print reduce(lambda x,y:x+y,[1,2,3,4])      # 結果為10
print reduce(lambda x,y:x+y,[1,2,3,4],10)   # 結果為20,init初始值為10

5 apply

>>> help(apply)
Help on built-in function apply in module __builtin__:

apply(...) 
    apply(object[, args[, kwargs]]) -> value

Call a callable object with positional arguments taken from the tuple args, and keyword arguments 
taken from the optional dictionary kwargs. Note that classes are callable, as are instances with
a __call__() method.Deprecated since release 2.3. Instead, use the extended call syntax:
function(*args, **keywords).

用途:

當一個函數的參數存在于一個元組或者一個字典中時,用來間接的調用這個函數,元組或者字典中的參數按照順序傳遞。

說明:

  • args是一個包含按照函數所需參數傳遞的位置參數的一個元組,假如func(a=1,b=2),那么這個元組中就必須嚴格按照這個參數的位置順序進行傳遞(a=3,b=4),而不能是(b=4,a=3)這樣的順序。
  • kwargs是一個包含關鍵字參數的字典,而其中args如果不傳遞,kwargs需要傳遞,則必須在args的位置留空。

apply函數的返回值就是func函數的返回值。其實apply(func,args,kwargs)從Python2.3開始,已經被function(*args,**kwargs)代替了。

例1. 常規使用

def func1():               # 無參函數 
    print 'No Args!'

def func2(arg1,arg2):      # 兩個參數 
    print arg1,arg2

def func3(arg1=1,arg2=2):  # 帶字典函數
    print arg1,arg2

if __name__=='__main__': 
    apply(func1) 
    apply(func2,('Hello','World!')) 
    apply(func3,(),{'arg1':'This is param1','arg2':'This is param2'})     # 注意元組參數為()

既然可以用function(args,*kwargs)來代替apply(),那么apply有什么好處呢,幾個看得見的好處:

  1. 如果函數名,變量名太長的話,用apply()還是很方便的。
  2. 如果不能確認有多少變量在args里面時,則必須使用apply,它能動態加載變量及函數。
# Sorry about the long variable names
args = function_returning_list_of_numbers()
func = function_returning_a_function_which_operates_on_a_list_of_numbers()

# You want to do f(arg[0], arg[1], ...) but you don't know how many arguments are in 'args'. For this you have to use 'apply': result = apply(func, args)

3.如果函數名作為一個對象來傳遞時,用apply()很方便。

def test(f,a,b): 
    print 'test' 
    print f(a,b)

test(func,a,b)

可以看出,test函數的第一個參數f就是一個函數對象。我們將func傳遞給f,那么test中的f()所做的實際上就是func()所實現的功能。這樣,就大大提供了程序的靈活性。假如我們有另外一個函數取代func,就可以使用相同的test函數。

test(lambda x,y: x ** 2 + y,2,3)
>>> test
7

6 zip

>>> help(zip)
Help on built-in function zip in module __builtin__:

zip(...) 
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

Return a list of tuples, where each tuple contains the i-th element from each of the argument
sequences. The returned list is truncated in length to the length of the shortest argument sequence.

用途:

返回一個元組列表,該元組按順序包含每個序列的相應元素,以最小的一個為準。

說明:

zip()是Python的一個內建函數,它接受一系列可迭代的對象作為參數,將對象中對應的元素打包成一個個tuple(元組),然后返回由這些tuples組成的list(列表)。若傳入參數的長度不等,則返回list的長度等于參數中長度最短的對象的長度。

例子:

>>> zip(range(5),range(1,20,2))
[(0, 1), (1, 3), (2, 5), (3, 7), (4, 9)]

>>> x=(1,2,3); y=(4,5);z=(6,)
>>> zip(x,y,z)
[(1, 4, 6)]

zip的邏輯實現:

def zip(*iterables): 
    sentinel = object() 
    iterators = [iter(it) for it in iterables] 
    while iterators:
        result = [] 
        for it in iterators: 
             elem = next(it, sentinel)
             if elem is sentinel: 
                  return result.append(elem) 
        yield tuple(result)

如果您發現文中有不清楚或者有問題的地方,請在下方評論區留言,我會根據您的評論,更新文中相關內容,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容