1. 程式人生 > >Python 高階函數 -- map/reduce

Python 高階函數 -- map/reduce

red python ascii https 依次 ng- print 計算 title

這個內容我是參考廖雪峰的博客,摘抄其中一些內容而來的,附帶解決他最後的問題代碼。

  1. 這是我在C/C++中未曾見過的語法(可能是我學藝未精),理解它確實花了十來二十分鐘。它提供了一條google的論文鏈接:“MapReduce: Simplified Data Processing on Large Clusters",據說是一篇很牛逼的文章。當我理解了這個概念後,覺得確實很方便。
  2. 先看map。map()函數接收兩個參數,一個是函數,一個是Iterablemap將傳入的函數依次作用到序列的每個元素,並把結果作為新的Iterator返回。

    舉例說明,比如我們有一個函數f(x)=x2,要把這個函數作用在一個list [1, 2, 3, 4, 5, 6, 7, 8, 9]

    上,就可以用map()實現如下:

                f(x) = x * x
    
                      │
                      │
      ┌────────────--------───┐
      │   │   │   │   │   │   │   │   │
      ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼
    
    [ 1    2    3    4    5    6    7    8    9 ]
    
      │   │   │   │   │   │   │   │   │
      │   │   │   │   │   │   │   │   │
      ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼
    
    [ 1    4    9   16    25   36   49   64   81 ]
    

    現在,我們用Python代碼實現:

    1 >>> def f(x):
    2 ...     return x * x
    3 ...
    4 >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    5 >>> list(r)
    6 [1, 4, 9, 16, 25, 36, 49, 64, 81]

    map()傳入的第一個參數是f,即函數對象本身。由於結果r是一個IteratorIterator是惰性序列,因此通過list()函數讓它把整個序列都計算出來並返回一個list。

  3. 再看reduce的用法。reduce把一個函數作用在一個序列[x1, x2, x3, ...]
    上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素做累積計算,其效果就是:
    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    比方說對一個序列求和,就可以用reduce實現:
    >>> from functools import reduce
    >>> def add(x, y):
    ...     return x + y
    ...
    >>> reduce(add, [1, 3, 5, 7, 9])
    25

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

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

  4. 練習

    1. 利用map()函數,把用戶輸入的不規範的英文名字,變為首字母大寫,其他小寫的規範名字。輸入:[‘adam‘, ‘LISA‘, ‘barT‘],輸出:[‘Adam‘, ‘Lisa‘, ‘Bart‘]
      #-*- coding: utf-8 -*-
      def normalize(name):
          return name.capitalize()
      
      # 測試:
      L1 = [adam, LISA, barT]
      L2 = list(map(normalize, L1))
      print(L2)

    2. Python提供的sum()函數可以接受一個list並求和,請編寫一個prod()函數,可以接受一個list並利用reduce()求積
      # -*- coding: utf-8 -*-
      from functools import reduce
      
      def prod(L):
          def fn(x,y):
              return x*y
          return reduce(fn,L)
      
      print(3 * 5 * 7 * 9 =, prod([3, 5, 7, 9]))
      if prod([3, 5, 7, 9]) == 945:
          print(測試成功!)
      else:
          print(測試失敗!)

    3. 利用mapreduce編寫一個str2float函數,把字符串‘123.456‘轉換成浮點數123.456
      # -*- coding: utf-8 -*-
      from functools import reduce
      
      def str2float(s):
          DIGITS = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
          pos = len(s)-s.index(".")-1 #尋找小數位
      
          def char2num(my_str):
              if(my_str != "."):
                  return DIGITS[my_str]
      
          def fn(x,y):
              if y==None:
                  return x
              else:
                  return 10*x+y
          return reduce(fn,map(char2num,s))/(10**pos)
      
      print(str2float(\‘123.456\‘) =, str2float(123.456))
      if abs(str2float(123.456) - 123.456) < 0.00001:
          print(測試成功!)
      else:
          print(測試失敗!)

Python 高階函數 -- map/reduce