一文看懂Python列表表達式及高階函數如lamda, zip, enumerate, map和filter方法.

2021-03-02 Python Web與Django開發

深入了解和熟練使用python的列表表達式和內置的一些高階函數如lamda, zip, enumerate, map, filter, reduce, sorted方法是python學習,面試和工作的必備技能。正是它們給了python優秀的特性,從而使python有別於其它程式語言。網上的介紹和教程有很多,但感覺還是比較零散,解讀也不夠深入,小編決定再次動手寫篇總結。如果大家還沒讀過小編寫的一文看懂python系列文章,請先閱讀一文看懂Python面向對象編程(Python學習與新手入門必看)-絕對原創和一文看懂Python對文件和文件夾的操作: 含os, shutil和glob模塊。Python學習面試必讀。本文內含很多實例代碼,以幫助新手更好理解。

列表表達式[List Comprehension]

顧名思義,這個表達式作用是以一個快捷的方法對列表進行操作或運算,返回新的列表。其使用方式為[表達式 for 變量 in 列表]  或者  [表達式 for 變量 in 列表 if 條件]。

一個最簡單的列表表達式的例子如下。

>>> list1 = [1, 2, 3, 4]
>>> list2 = [ i*i for i in list1]
>>> list3 = [ i*i for i in list1 if i>2]
>>> print(list2)
[1, 4, 9, 16]
>>> print(list3)
[9, 16]

列表表達式也可以遍曆元組生成新的列表(如list5),然而卻不能直接生成新的元組。比如list6實際上是個生成器表達式,不屬於列表表達式了。對於生成器表達式可以通過使用list6.__next__()方法一次一次取值。

>>> tuple1 = (1, 2, 3, 4)
>>> list5 = [ i*i for i in tuple1 ]
>>> print(list5)
[1, 4, 9, 16]
>>> list6 = ( i*i for i in tuple1 )
>>> print(list6)
<generator object <genexpr> at 0x03559E10>

下面我們來看下3個常考的關於列表表達式應用的例子。

1.統計字符串列表中每個字符串的長度

>>> words = ['abc','defg','I love python', 'Django']
>>> len_list = [ len(word) for word in words ]
>>> print(len_list)
[3, 4, 13, 6]

2. 利於列表表達式求兩個列表的交集。

>>> a = [ 3, 5, 6, 8]
>>> b = [ 5, 6]
>>> a_b = [ i for i in a if i in b]
>>> print(a_b)
[5, 6]

3. 列印出100以內所有十位數比個位數大1位的數字。

>>> num = [ n1*10+n2 for n1 in range(0, 10)
       for n2 in range(0, 10) if n1 == n2+1 ]
>>> print(num)
[10, 21, 32, 43, 54, 65, 76, 87, 98]

匿名函數lambda函數

Lambda函數又稱匿名函數,也有人稱為lambda表達式。顧名思義,匿名函數就是沒有名字的函數。函數沒有名字也行?當然可以啦。有些函數如果只是臨時一用,而且它的業務邏輯也很簡單時,就沒必要非給它取個名字不可。

lambda匿名函數的格式是 lambda 參數: 表達式。冒號前是參數,可以有多個,用逗號隔開,冒號右邊的為表達式。其實lambda返回值是一個函數的地址,也就是函數對象。下面是個最簡單的lambda函數的例子。

>>> add = lambda x, y: x+y
>>> type(add)
<class 'function'>
>>> print(add(3,5))
8

既然是匿名函數,我們為什麼還要給它取個叫add的名字?這的確是多次一舉。其實lambda最常用的還是和sorted, map、reduce、filter這些高級函數結合使用。我們再來看下2個使用lambda函數結合sorted方法排序的經典例子。一個按絕對值大小排序,一個按字符串長度排序。

>>> list1 = [ 5, -3, 1, 8, -4 ]
>>> list2 = sorted(list1, key=lambda x:abs(x))
>>> print(list2)
[1, -3, -4, 5, 8]

>>> list3 = [ 'to', 'python', 'ABC' ]
>>> list4 = sorted(list3, key=lambda x:len(x))
>>> print(list4)
['to', 'ABC', 'python']

下面是一道關於lambda函數的經典面試題。flist[0]能輸出什麼?這個主要考函數對象列表,千萬不要和列表表達式搞混了啊。答: flist[0]輸出的是函數對象。

>>> flist = [ lambda x:x*x for x in range(1, 3)]
>>> print(flist)
[<function <listcomp>.<lambda> at 0x03ADE2B8>, <function <listcomp>.<lambda> at 0x03ADE300>]
>>> flist[0]
<function <listcomp>.<lambda> at 0x03ADE2B8>
>>> flist[0](2)
4

zip函數

zip()函數來可以把2個或多個列表合併,並創建一個元組對的列表。元組對的數量以合併列表的最短長度為準。python 3中zip方法合併列表後生成的是zip對象,使用list方法可以將其變成列表,使用dict方法可以將其變成字典。

>>> l1 = [ 1, 2, 3 ]
>>> l2 = [ 'x', 'y', 'z']
>>> l3 = [ 'x', 'y' ]
>>> zip(l1, l2)
<zip object at 0x031D6828>
>>> print(list(zip(l1, l2)))
[(1, 'x'), (2, 'y'), (3, 'z')]
>>> print(list(zip(l1, l3)))
[(1, 'x'), (2, 'y')]
>>> print(dict(zip(l1,l3)))
{1: 'x', 2: 'y'}

實際上zip方法支持所有可迭代對象(字符串、列表、元祖、字典), 而不僅僅是列表。利用這個特性,我們可以很容易創建各種字典,包括很複雜的字典。我們來看下面2個經典例子。注意zip對象支持直接遍歷哦,不需要先轉成list或dict哦。

>> > l1 = [1, 2, 3]
>> > str1 = "abc"
>> > print(dict(zip(l1, str1)))
{1: 'a', 2: 'b', 3: 'c'}
>> > name = ["John", "Jim", "Lucy"]
>> > year = [1983, 1985, 1995]
>> > birth_year = dict(zip(name, year))
>> > print(birth_year)
{'John': 1983, 'Jim': 1985, 'Lucy': 1995}
>> > for name, year in zip(name, year):
   print("{} - {}".format(name, year))

John - 1983
Jim - 1985
Lucy - 1995

利用zip(*some_list)方法可以實現元組列表的反向解壓,見下面案例。注意unzip只支持元組列表,不支持dict直接解壓哦。這也是面試常考內容。

>>> l1 = [("John", 1995), ("Lucy", 2000), ("Max", 1985)]
>>> name, year = zip(*l1)
>>> print(name)
('John', 'Lucy', 'Max')
>>> print(year)
(1995, 2000, 1985)
>>> l2 = dict(l1)
>>> print(l2)
{'John': 1995, 'Lucy': 2000, 'Max': 1985}
>>> name1, year1 = zip(*l2)
Traceback (most recent call last):
 File "<pyshell#6>", line 1, in <module>
   name1, year1 = zip(*l2)
ValueError: too many values to unpack (expected 2)

enumerate() 函數

enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,常見用於for循環。一般只有需要同時用到索引index和value值的時候才用enumerate方法。注意直接使用enumerate方法生成是個enumerate對象,可以遍歷的。

>> > name = ["John", "Lucy", "Mary"]
>> > name1 = enumerate(name)
>> > print(name1)
< enumerate object at 0x030D0FA8 >
>> > for index, name in enumerate(name):
   print("{}-{}".format(index, name))

0 - John
1 - Lucy
2 - Mary

map函數

map函數是個非常有用的方法,其語法是 map(function, iterable, ...)。map方法可以接收函數作為參數,並將其映射於列表的多個元素。python 2中返回列表,python 3中返回迭代器,需要使用list方法再生成列表。map函數不僅支持自定義的函數和lambda函數,還支持python自帶的函數。

下面是map函數應用一個最簡單的例子。該例子將計算平方的lambda函數映射於列表中的每個元素。

>>> l = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
>>> print(l)
<map object at 0x03553790>
>>> print(list(l))
[1, 4, 9, 16, 25]

map函數還支持多個列表的映射和計算,如下所示。lambda函數中的x, y, z分別對應列表l1, l2和l3中的元素。計算後的生成的列表長度取決於各個列表的最短長度。

>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6, 7]
>>> l3 = [8, 9]
>>> print(list(map(lambda x,y,z:x+y+z, l1, l2, l3)))
[13, 16]

我們下面來看下一道關於map函數的經典考題。我們有兩個字符串A和B,現在要統計字符串A中有多少個字符也在字符串B中可以找到。常規函數解法如下:

>>> strA = "aAAAbBCC"
>>> strB = "aA"
>>> def count1(str1, str2):
  a = 0
  for c in str1:
     if c in str2:
        a += 1
  return a

>>> count1(strA, strB)
4

使用map函數經典解法如下,是不是好簡單好牛叉的樣子?

>>> strA = "aAAAbBCC"
>>> strB = "aA"
>>> print(sum(map(strA.count, strB)))
4

我們現在來分析下上面這段代碼。python自帶的string.count(char)函數的作用是統計一個字符串string含有字符char的數量。在本例中strB相當於char的一個參數列表["a", "A"], map函數先統計strA中字符a的數量,再統計strA中字符A的數量,獲得列表[1, 3], 然後將它們相加,即可獲得字符串A中總共有多少字符可以在B中找到。

reduce函數

reduce() 函數會對參數序列中元素進行累積。該方法第一個參數必需是函數,而且傳入的函數必需要有2個參數,否則出現錯誤。該方法將一個數據集合(列表,元組等)中的所有數據進行下列操作:用傳給 reduce 中的函數 function先對集合中的第 1、2 個元素進行操作,得到的結果再與第三個數據用 function 函數運算,最後得到一個結果。

reduce函數很適合連續計算(比如列表求和或連乘計算階乘),經典代碼如下。

>>> from functools import reduce
>>> reduce(lambda x, y: x+y, [1,2,3,4,5])
15
>>> reduce(lambda x,y:x*y,range(1,5))
24

注意: python 3中reduce() 函數已經被從全局名字空間裡移除了,它現在被放置在 fucntools 模塊裡,如果想要使用它,則需要通過引入 functools 模塊來調用 reduce() 函數。

filter函數

Python的 filter() 函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。該方法與map和reduce類似,第一個參數都是函數,作用於可以迭代的對象比如列表和元組,但不同的是filter方法傳入的函數是判斷性函數, 只有符合條件的列表元素才會加入新的列表。Python 2中返回列表,python 3中返回filter對象,使用list方法可以轉化為列表。

下面是使用filter方法列印出10以內偶數的經典代碼。只有滿足x % 2 == 0 的列表元素才會加入新的列表。

>>> l = filter(lambda x: x % 2 == 0, range(10))
>>> print(l)
<filter object at 0x02C0BBF0>
>>> print(list(l))
[0, 2, 4, 6, 8]

下面這段代碼利用filter方法刪除字符串列表裡的空白字符串。只有滿足s and s.strip() = True的字符串才會加入新的列表。

def not_empty(s):
   return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
# 結果: ['A', 'B', 'C']

最好一道是關於filter方法的經典面試題,利用filter方法篩選出一個列表中的素數。網上大多數代碼都不完美,一是不能對小於等於2的數(包括0, 1和2)做出準確判斷,二是使用了for i in range(2, n+1),做了很多無效循環。

>>> import math
>>> def isPrime(n):
      if n <= 1:
         return False
      elif n == 2:
         return True
      else:
         for i in range(2, int(math.sqrt(n))+1):
            if n%i == 0:
               return False
         return True

>>> l1 = [-1, 0, 2, 3, 6, 7, 8]
>>> l2 = list(filter(isPrime, l1))
>>> print(l2)
[2, 3, 7]

小結

本文詳細總結了python的列表表達式及常用高階函數如lambda, zip, map, enumerate, reduce, filter的用法。你學了嗎?看懂的點個讚,沒看懂的留個言啊。如果覺得特別贊的,行個賞啊。接下來本博客會分3個系列連載,分別為Django系列,一文看懂Python基礎系列和Python爬蟲系列,歡迎關注。

大江狗

2018.8.27

相關焦點

  • python高階函數:map、filter、reduce的替代品
    什麼是高階函數?高階函數是一種將函數作為參數,或者把函數作為結果返回的函數,map函數、sorted函數就是高階函數的典型例子。map函數在小編以前的文章中做過相應的知識分享。sorted函數是python的內置函數,它的可選參數key用於提供一個函數,它可以將函數應用到各個元素上進行排序。
  • 科學使用python中的Map函數和Filter函數
    實現此目的的一種方法是使用for循環遍歷數字列表,並返回每個數字或每個元素的平方。 並且,在遍歷列表時,將平方值添加到新列表中。 我們使用for循環遍歷num_list,並將num_list每個元素的平方附加到num_list_squared列表中。完成此操作的另一種方法是使用內置的 python 函數 map。Map 函數接受兩個參數: 我們要應用的函數和我們要應用它的迭代對象或序列(例如本例中的列表)。換句話說,map 函數映射或應用這個函數到我們傳入的序列的每個元素。
  • Python中有哪些內置函數呢?以及內置函數實例
    高級內置函數enumerate 返回一個可以枚舉的對象eval 取出 字符串中的內容,將字符串str當成有效的表達式來求指並返回計算結果exec 執行字符串或complie方法編譯過的字符串
  • Python最重要的5大功能,要是能早點了解就好了!
    列表推導——緊緻碼很多人認為lambda、map和filter是每個初學者都應該學習的函數。雖然筆者認為這些函數值得關注,但是由於它們缺乏靈活性,大多時候不是特別有用。Lambda是將一次性使用的函數生成為一行的方法。若函數被多次調用,性能就會降低。另一方面,map將一種函數應用於列表中的所有元素,而filter則會獲取集合中滿足用戶定義條件的元素子集。
  • Python高階函數使用總結!
    本文結合各種實際的例子詳細講解了Python5個內建高階函數的使用,能夠幫助理解Python的數據結構和提高數據處理的效率,這5個函數分別是:一、map1.1 語法map函數的基本語法是map(func, seq),其含義指的是:對後面可迭代序列中的每個元素執行前面的函數func的功能,最終獲取到一個新的序列
  • Python中10個常用的內置函數
    complex()返回一個形如 a+bj 的複數,傳入參數分為三種情況:參數為字符串時,將字符串表達式解釋為複數形式並返回參數只有一個整數 a 時,虛部 b 默認為0,函數返回 a+0j>>> complex('1+2j')(1+2j)>>
  • Python 中 10 個常用的內置函數
    返回一個形如 a+bj 的複數,傳入參數分為三種情況:參數為字符串時,將字符串表達式解釋為複數形式並返回參數只有一個整數 a 時,虛部 b 默認為0,函數返回 a+0j>>> complex('1+2j')(1+2j)>>> complex()0j
  • Python中map函數的解釋和可視化
    Python中zip()函數的解釋和可視化Python中enumerate函數的解釋和可視化先重溫一下迭代(Iteration)、迭代器對象(iterable)、迭代器(iterator )的概念:譯者註:map()函數在python2中返回的是列表。
  • 讓你的代碼更「地道」:提高Python編碼水平的小技巧
    雖然可以用for循環語句來實現,但是還有一種更簡單直接的方法。與上述情況類似,當某個功能可用於某個序列時,通常意味著字符串、元組和列表也都支持這個功能。創建生成器的一種特殊方法稱為生成器表達式。除了用圓括號而非方括號這一點外,生成器表達式在語法上與列表解析式類似。
  • 【Python基礎】Python初學者必須吃透這69個內置函數!
    enumerate()描述:enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,一般用在for循環當中。>filter()描述:filter() 函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。
  • 詳解Python函數式編程之map、reduce、filter
    不過,在Python 3.x中,reduce()不是內置函數,而是放到了標準庫functools中,需要先導入再使用。(1)map()。內置函數map()可以將一個函數依次映射到序列或迭代器對象的每個元素上,並返回一個可迭代的map對象作為結果,map對象中每個元素是原序列中元素經過該函數處理後的結果,該函數不對原序列或迭代器對象做任何修改。
  • 打基礎一定要吃透這12類 Python 內置函數
    內置函數就是python給你提供的, 拿來直接用的函數,比如print.,input等。截止到python版本3.6.2 python一共提供了68個內置函數,我將它們分成 12 類,方便你學習。1. 和數字相關1.
  • Python初學者必須吃透這69個內置函數!
    ()描述:enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,一般用在for循環當中。>filter()描述:filter() 函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。
  • Python編程技巧:如何用Map, Filter, Reduce代替For循環?
    map、filter 和 reduce 這三種技術可以提供描述迭代原因的函數替代方案,以便避免過多的 for 循環。我之前在 JavaScript 中寫過這些技術的入門文章,但是它們在 Python 中的實現略有不同。
  • 5 個越早知道越好的 Python 特性
    1.理解 List——壓縮代碼很多人會將 lambda、map 和 filter 作為 Python 的「技巧」,每個初學者都應該學習這些技巧。雖然我相信它們是我們應該掌握的特性,但我發現由於缺乏靈活性,它們在大多數時候並不特別有用。
  • Python語言中enumerate()及zip()函數的使用例子
    在Python程式語言中,enumerate()及zip()是兩個常用的內置函數,這兩個函數功能類似,但又有所區別,下面通過兩個例子分別進行說明。enumerate()函數該函數在字面上是枚舉、列舉的意思,用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,一般用在 for 循環當中,可同時得到數據對象的值及對應的索引值。
  • Python 打基礎一定要吃透這 5 個內置函數
    查看幫助文檔將序列中的每個元素傳遞給函數,執行的結果為 True或者 False,將結果為 True的元素放入新的列表中。返回的是 filter對象。如果想看具體的數據,需要使用 list來展開。help(filter)
  • Python數據分析常用高階函數大全
    >和map類似,zip返回的也是一個zip的元組迭代器對象,我們需要使用list將它的元素釋放出來filterfilter(function,sequence)第一個參數是函數,第二個參數是可迭代對象long=[1,2,3,4,5]list(filter(lambdax:x%2==0,long))# 找出偶數。# filter函數返回的是迭代器,所以需要用list轉換,進行釋放元素。
  • Python入門基礎之map()、reduce()函數使用
    1、 map()函數map()是 python 內置的高階函數,它接收一個函數 f 和一個 list,並通過把函數 f 依次作用在 list 的每個元素上,得到一個新的object並返回。(python2返回列表,Python3返回迭代對象)map()的使用方法形如map(f(x),Itera),它有兩個參數,第一個參數為某個函數,第二個為可迭代對象。
  • 如何用Map、Filter和Reduce替換Python For循環?
    在Python中,這三種技術易函數的形式存在,而不是Array或String類的方法。這意味著要寫成map(function, my_list)而不是my_array.map(function)。此外,每個技術都需要傳遞函數,該函數會被每個項執行。