天天看點

Python函數式程式設計-map()、zip()、filter()、reduce()、lambda()

三個函數比較類似,都是應用于序列的内置函數。常見的序列包括list、tuple、str

map函數

map函數會根據提供的函數對指定序列做映射。

map函數的定義:

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

map()函數接收兩個參數,一個是函數,一個是序列,map将傳入的函數依次作用到序列的每個元素,并把結果作為新的list傳回。

1、當seq隻有一個時,将函數func作用于這個seq的每個元素上,并得到一個新的seq。

讓我們來看一下隻有一個seq的時候,map()函數是如何工作的。

Python函數式程式設計-map()、zip()、filter()、reduce()、lambda()

示例一

比如要對一個序列中的每個元素進行平方運算:

傳回結果為:

[, , , , ]
           

或者

>>> def f(x):
...   return x * x
...
>>> map(f, [, , , , ])
[, , , , ]
           

map()傳入的第一個參數是f,即函數對象本身。

注意:map()函數不改變原有的 list,而是傳回一個新的 list。

不需要map()函數,寫一個循環,也可以計算出結果

L = []
for n in [, , , , ]:
  L.append(f(n))
print L
           

把f(x)作用在list的每一個元素并把結果生成一個新的list。

示例二

#使用lambda
>>> print map(lambda x: x % , range())
[, , , , , , ]
           
#使用清單解析
>>> print [x %  for x in range()]
[, , , , , , ]
           

2、當seq多于一個時,map可以并行(注意是并行)地對每個seq執行如下圖所示的過程

Python函數式程式設計-map()、zip()、filter()、reduce()、lambda()

在參數存在多個序列時,會依次以每個序列中相同位置的元素做參數調用function函數。

示例

比如要對兩個序列中的元素依次求和。

map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
           

map傳回的list中第一個元素為,參數序列1的第一個元素加參數序列2中的第一個元素(1 + 2),

list中的第二個元素為,參數序列1中的第二個元素加參數序列2中的第二個元素(3 + 4),

依次類推,最後的傳回結果為:

[, , , , ]
           

要注意function函數的參數數量,要和map中提供的集合數量相比對。

如果集合長度不相等,會以最小長度對所有集合進行截取。

當函數為None時,操作和zip相似:

map(None, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
           

傳回結果為:

[(, ), (, ), (, ), (, ), (, )]
           

map()作為高階函數,事實上它把運算規則抽象了,是以,我們不但可以計算簡單的f(x)=x2,還可以計算任意複雜的函數,比如,把這個list所有數字轉為字元串:

>>> map(str, [, , , , , , , , ])
['1', '2', '3', '4', '5', '6', '7', '8', '9']
           

由于list包含的元素可以是任何類型,是以,map() 不僅僅可以處理隻包含數值的 list,事實上它可以處理包含任意類型的 list,隻要傳入的函數f可以處理這種資料類型。

比如假設使用者輸入的英文名字不規範,沒有按照首字母大寫,後續字母小寫的規則,請利用map()函數,把一個list(包含若幹不規範的英文名字)變成一個包含規範英文名字的list:

輸入:[‘adam’, ‘LISA’, ‘barT’]

輸出:[‘Adam’, ‘Lisa’, ‘Bart’]

def format_name(s):
    s1=s[:].upper()+s[:].lower();
    return s1;

print map(format_name, ['adam', 'LISA', 'barT'])
           
***将元組轉換成list***
>>> map(int, (,,))
[, , ]
***将字元串轉換成list***
>>> map(int, '1234')
[, , , ]
***提取字典的key,并将結果存放在一個list中***
>>> map(int, {:,:,:})
[, , ]
***字元串轉換成元組,并将結果以清單的形式傳回***
>>> map(tuple, 'agdf')
[('a',), ('g',), ('d',), ('f',)]
#将小寫轉成大寫
def u_to_l (s):
  return s.upper()
print map(u_to_l,'asdfd')
           

zip函數

Python函數式程式設計之zip()

zip()函數具體的工作機制是,将每個清單中同一位置的元素取出來組成一個元組,存放到一個清單中,然後傳回這個清單。

>>> x = [,,]
>>> y = ['a','b','c']
>>> z = [,,]
>>> zip_xyz = zip(x, y, z)
>>> print zip_xyz
[(, 'a', ), (, 'b', ), (, 'c', )]
           

對于長度不同的seq,zip()函數又怎麼處理呢?

>>> a = [,,]
>>> b = [,,,]
>>> zip_ab = zip(a, b)
>>> print zip_ab
[(, ), (, ), (, )]
           

從上面的例子可以看出,當seq的長度不一緻時,zip()會以最短的那個seq為主,進行處理,然後将多餘的舍棄掉。

zip()對隻有一個seq的處理:

>>> c = ['a', 'b', 'c']
>>> zip_c = zip(c)
>>> print zip_c
[('a',), ('b',), ('c',)]
           

unzip

>>> a = [, , ]
>>> b = ['a', 'b', 'c']
>>> zip_ab = zip(a,b)
>>> un_zip = zip(*zip_ab)
>>> print un_zip
[(, , ), ('a', 'b', 'c')]
           

一般認為這是一個unzip過程,工作原理如下:

在運作zip(*zip_ab)之前,zip_ab的值是:[(1, ‘a’), (2, ‘b’), (3, ‘c’)]

而zip(*zip_ab)就等價于zip((1, ‘a’), (2, ‘b’), (3, ‘c’))

是以得出結果:[(1, 2, 3), (‘a’, ‘b’, ‘c’)]

>>> x = [,'a','b']
>>> zip_rx = zip(* [x] * )
>>> print zip_rx
[(, , ), ('a', 'a', 'a'), ('b', 'b', 'b')]
           

首先 [x]生成一個清單的清單:[[1, ‘a’, ‘b’]],這個清單中隻有一個元素[1,’a’,’b’]

其次[x] * 3,表示将清單中的元素列印三次,即生成了含有三個元素的清單:

[[1, ‘a’, ‘b’], [1, ‘a’, ‘b’], [1, ‘a’, ‘b’]]

最後是zip(* [x] * 3)就等價于

zip([1, ‘a’, ‘b’], [1, ‘a’, ‘b’], [1, ‘a’, ‘b’])

filter函數

filter函數會對指定序列執行過濾操作。

filter函數的定義:

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

filter函數會對序列參數sequence中的每個元素調用function函數,最後傳回的結果包含調用結果為True的元素序列。傳回值的類型和參數sequence的類型相同. func函數是一個布爾函數,filter()函數調用這個函數一次作用于seq中的每一個元素,篩選出符合條件的元素,并以清單的形式傳回。

示例一

比如傳回序列中的所有偶數:

def is_even(x):
return x &  != 

filter(is_even, [, , , , , , , , , ])
           

傳回結果為:

[1, 3, 5, 7, 9]

如果function參數為None,傳回結果和sequence參數相同。

示例二

假如有個清單,清單中有幾個數字,現在我想從這些數字中,選出即能被2整除又能被3整除的數。

nums = [,,,,,]
def nums_res (x):
  return x %  ==  and x %  == 
print filter(nums_res, nums)
執行結果:[, , ]
           

如果使用普通方法的話,就需要使用for循環去挨個挨個周遊list中的元素。當然我們也可以使用清單解析法:

>>> print [x for x in nums if x %  ==  and x %  == ]
[, , ]
           

reduce函數

reduce函數,即為化簡函數,reduce函數會對參數序列中元素進行累積。

reduce函數的定義:

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

function參數是一個有兩個參數的函數,reduce依次從sequence中取一個元素,和上一次調用function的結果做參數再次調用function。

第一次調用function時,如果提供initial參數,會以sequence中的第一個元素和initial作為參數調用function,否則會以序列sequence中的前兩個元素做參數調用function。

reduce()函數的執行過程如下圖所示

Python函數式程式設計-map()、zip()、filter()、reduce()、lambda()

reduce把一個函數作用在一個序列[x1, x2, x3…]上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素做累積計算,其效果就是:

示例一

比方說對一個序列求和,就可以用reduce實作

>>> def add(x, y):
...   return x + y
...
>>> reduce(add, [, , , , ])

           

或者

結果為25

或者

結果為25( ((((1+3)+5)+7)+9) )

當然求和運算可以直接用Python内建函數sum(),沒必要動用reduce。

示例二

從reduce函數的執行過程,很容易聯想到求一個數的階乘,而python中并沒有給出一個求階乘的内置函數,正好就拿這個例子來說明reduce函數。

#未指定init的情況
>>> n = 
>>> print reduce(lambda x, y: x * y, range(, n))

           

上面的例子中range(1,6)函數生成的是一個[1, 2, 3, 4, 5]這樣的清單,這裡我們給它個名叫seq1吧,reduce()函數執行時,由于沒有指定init參數,是以将取seq1中的第一個元素1,作為第一個元素,由于前面的lambda有2個變量,是以需要兩個實參,于是就取seq1中的第2個元素2,與第一個元素1一起傳入lambda中去執行,并将傳回結果2,并同下一個元素3再一起傳入lambda中執行,再次傳回的結果,作為下一次執行的第一個元素,依次類推,就得出結果5! = 120。

如果我們希望得到階乘的結果再多增加幾倍,可以啟用init這個可選項。如:

>>> print reduce(lambda x, y: x * y, range(, n),)

           

這個時候,就會将init作為第一個元素,和seq1中的第一個元素1一起傳入lambda函數中去執行,傳回結果再作為下一次的第一個元素。

但是如果要把序列[1, 3, 5, 7, 9]變換成整數13579,reduce就可以派上用場

>>> def fn(x, y):
...   return x *  + y
...
>>> reduce(fn, [, , , , ])

           

這個例子本身沒多大用處,但是,如果考慮到字元串str也是一個序列,對上面的例子稍加改動,配合map(),我們就可以寫出把str轉換為int的函數:

>>> def fn(x, y):
...   return x *  + y
...
>>> def char2num(s):
...   return {'0': , '1': , '2': , '3': , '4': , '5': , '6': , '7': , '8': , '9': }[s]
...
>>> reduce(fn, map(char2num, '13579'))

           

整理成一個str2int的函數就是:

def str2int(s):
  def fn(x, y):
    return x *  + y
  def char2num(s):
    return {'0': , '1': , '2': , '3': , '4': , '5': , '6': , '7': , '8': , '9': }[s]
  return reduce(fn, map(char2num, s))
           

還可以用lambda函數進一步簡化成

def char2num(s):
  return {'0': , '1': , '2': , '3': , '4': , '5': , '6': , '7': , '8': , '9': }[s]
           
def str2int(s):
  return reduce(lambda x,y: x*+y, map(char2num, s))
           

也就是說,假設Python沒有提供int()函數,你完全可以自己寫一個把字元串轉化為整數的函數,而且隻需要幾行代碼

注意function函數不能為None。

lambda函數

Python中,lambda函數也叫匿名函數,及即沒有具體名稱的函數,它允許快速定義單行函數,類似于C語言的宏,可以用在任何需要函數的地方。這差別于def定義的函數。

lambda與def的差別:

1)def建立的方法是有名稱的,而lambda沒有。

2)lambda會傳回一個函數對象,但這個對象不會賦給一個辨別符,而def則會把函數對象指派給一個變量(函數名)。

3)lambda隻是一個表達式,而def則是一個語句。

4)lambda表達式” : “後面,隻能有一個表達式,def則可以有多個。

5)像if或for或print等語句不能用于lambda中,def可以。

6)lambda一般用來定義簡單的函數,而def可以定義複雜的函數。

6)lambda函數不能共享給别的程式調用,def可以。

lambda文法格式:

lambda 變量 : 要執行的語句

lambda [arg1 [, agr2,…..argn]] : expression

、單個參數的:
>>> g = lambda x : x ** 
>>> print g()

、多個參數的:
>>> g = lambda x, y, z : (x + y) ** z
>>> print g(,,)

           

lambda表達式會傳回一個函數對象,如果沒有變量接受這個傳回值的話,它很快就會被丢棄。也正是由于lambda隻是一個表達式,是以它可以直接作為list和dict的成員。如:

>>> list_a = [lambda a: a**, lambda b: b**]
>>> list_a[]
<function <lambda> at >
>>> g = list_a[]
>>> g()

           

lambda表達式中,冒号前面是參數,可以有多個,用逗号分隔,冒号右邊是傳回值。

參考文獻

python中的map、filter、reduce函數

python map函數

Python map()函數的用法

Python reduce()函數的用法

Python filter()函數的用法

Python lambda函數的用法