zoukankan      html  css  js  c++  java
  • [译]PYTHON FUNCTIONS

    map, filter, and reduce

    Python提供了几个函数,使得能够进行函数式编程。这些函数都拥有方便的特性,他们可以能够很方便的用python编写。
    函数式编程都是关于表达式的。我们可以说,函数式编程是一种面向表达式的编程。

    Python提供的面向表达式的函数有:
    map(aFunction, aSequence)
    filter(aFunction, aSequence)
    reduce(aFunction, aSequence)
    lambda
    list comprehension

    map
    我们对list和其他sequence所做的常见事情之一是对每个item应用操作并收集结果。
    例如,可以使用for循环轻松完成更新list中的所有items的更新操作:

    >>> items = [1, 2, 3, 4, 5]
    >>> squared = []
    >>> for x in items:
    	squared.append(x ** 2)
    >>> squared
    [1, 4, 9, 16, 25]
    

    由于这是一个常见的操作,实际上我们有一个内置的功能,可以替我们完成大部分的工作。
    map(aFunction,aSequence)函数将传入的函数应用于可迭代对象中的每个item,并返回一个包含所有函数调用结果的list。

    >>> items = [1,2,3,4,5]
    >>> def sqr(x):return x ** 2
    >>> list(map(sqr,items))
    [1,4,9,16,25]
    

    我们通过一个用户定义的函数应用于list的每个item。 map调用每个list中item上的sqr,并将所有返回值收集到一个新list中。因为map需要传入一个函数,所以它也恰好是lambda常规用的地方之一:

    >>> list(map((lambda x: x **2), items))
    [1, 4, 9, 16, 25]
    

    在上面的简短示例中,lambda函数给列表中的每个item都做了平方运算。如前所述,map是这样定义的:
    map(aFunction, aSequence)

    尽管我们仍然使用lamda作为函数,但我们可以将函数列表作为序列:

    def square(x):
            return (x**2)
    def cube(x):
            return (x**3)
    
    funcs = [square, cube]
    for r in range(5):
        value = map(lambda x: x(r), funcs)
        print value
    

    输出结果:

    [0,0]
    [1,1]
    [4,8]
    [9,27]
    [16,64]
    

    因为使用map等价于循环,所以我们总是可以编写一个通用的映射工具:

    >>> def mymap(aFunc, aSeq):
    	result = []
    	for x in aSeq: result.append(aFunc(x))
    	return result
    
    >>> list(map(sqr, [1, 2, 3]))
    [1, 4, 9]
    >>> mymap(sqr, [1, 2, 3])
    [1, 4, 9]
    >>> 
    

    由于map是内置的,所以它始终可用,并始终以相同的方式工作。它也有一些性能上的好处,因为它通常比手动编码的循环更快。除此之外,map可以以更高级的方式使用。例如,在给定多个序列参数的情况下,它将并行采取的项目作为不同的参数发送给函数:

    >>> pow(3,5)
    243
    >>> pow(2,10)
    1024
    >>> pow(3,11)
    177147
    >>> pow(4,12)
    16777216
    >>> 
    >>> list(map(pow, [2, 3, 4], [10, 11, 12]))
    [1024, 177147, 16777216]
    >>> 
    

    如上例所示,对于多个序列,map()需要N个序列的N参数函数。在这个例子中,pow函数在每个调用中都有两个参数。

    下面是另一个map()做两个列表元素添加的例子:

    x = [1,2,3]
    y = [4,5,6]
    
    from operator import add
    print map(add, x, y)  # output [5, 7, 9]
    

    地图调用类似于列表理解表达式。但是map对每个项目应用了一个函数调用,而不是一个任意的表达式。由于这个限制,它是不太一般的工具。然而,在某些情况下,映射可能比列表解析式更快,比如映射内置函数。而且map需要更少的编码。
    如果函数是None,则假定身份函数;如果有多个参数,则map()返回一个包含所有迭代(一种转置操作)中相应项目的元组的列表。可迭代的参数可能是一个序列或任何可迭代的对象;结果总是一个列表。

    >>> m = [1,2,3]
    >>> n = [1,4,9]
    >>> new_tuple = map(None, m, n)
    >>> new_tuple
    [(1, 1), (2, 4), (3, 9)]
    

    对于Python3,我们可能想使用itertools.zip_longest来代替:

    >>> m = [1,2,3]
    >>> n = [1,4,9]
    >>> from itertools import zip_longest
    >>> for i,j in zip_longest(m,n):
    ...    print(i,j)
    ... 
    1 1
    2 4
    3 9
    

    zip_longest()使得迭代器聚合来自两个迭代器(m&n)的元素。

    filter、reduce
    顾名思义,filter提取函数返回True的序列中的每个元素。减少函数的意图稍微不明显。该功能通过提供的功能组合元素将列表缩小为单个值。 map函数是用于函数式编程的Python内建函数中最简单的函数。
    这些工具将函数应用于序列和其他迭代。filter根据作为过滤器的测试功能过滤出iterm,并将功能应用到item对和减少的运行结果。因为他们返回迭代器,范围和过滤器都需要列表调用,以在Python 3.0中显示所有的结果。

    例如,下面的filter调用会挑选出序列中小于零的项目:

    >>> list(range(-5,5))
    [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
    >>>
    >>> list( filter((lambda x: x < 0), range(-5,5)))
    [-5, -4, -3, -2, -1]
    >>> 
    

    在该函数返回true的序列或迭代中的项目,结果被添加到结果列表。像map一样,这个函数大致相当于一个for循环,但它是内置的和快速的:

    >>> result = []
    >>> for x in range(-5, 5):
    	if x < 0:
    		result.append(x)
    
    		
    >>> result
    [-5, -4, -3, -2, -1]
    

    这里是filter()的另一个用例:找到两个列表的交集:

    a = [1,2,3,5,7,9]
    b = [2,3,5,6,7,8]
    print filter(lambda x: x in a, b)  # prints out [2, 3, 5, 7]
    

    请注意,我们可以在列表理解上做同样的事情:

    a = [1,2,3,5,7,9]
    b = [2,3,5,6,7,8]
    print [x for x in a if x in b] # prints out [2, 3, 5, 7]
    

    reduce是Python 3.0中的functools。这是更复杂的。它接受一个迭代器来处理,但它本身不是一个迭代器。它返回一个单一的结果:

    >>> from functools import reduce
    >>> reduce( (lambda x, y: x * y), [1, 2, 3, 4] )
    24
    >>> reduce( (lambda x, y: x / y), [1, 2, 3, 4] )
    0.041666666666666664
    

    在每个步骤中,减少将当前产品或部门以及列表中的下一个项目传递给传入的lambda函数。默认情况下,序列中的第一个项目初始化起始值。
    这里是第一个调用的for循环版本,在循环内部进行了硬编码:

    >>> L = [1, 2, 3, 4]
    >>> result = L[0]
    >>> for x in L[1:]:
    	result = result * x
    >>> result
    24
    

    让我们来制作我们自己的reduce版本。

    >>> def myreduce(fnc, seq):
    	tally = seq[0]
    	for next in seq[1:]:
    		tally = fnc(tally, next)
    	return tally
    
    >>> myreduce( (lambda x, y: x * y), [1, 2, 3, 4])
    24
    >>> myreduce( (lambda x, y: x / y), [1, 2, 3, 4])
    0.041666666666666664
    >>> 
    

    我们可以连接一串字符串来做一个句子。使用迪杰斯特拉关于错误的着名报价:

    import functools
    >>> L = ['Testing ', 'shows ', 'the ', 'presence', ', ','not ', 'the ', 'absence ', 'of ', 'bugs']
    >>> functools.reduce( (lambda x,y:x+y), L)
    'Testing shows the presence, not the absence of bugs'
    >>> 
    
    We can get the same result by using join :
    >>> ''.join(L)
    'Testing shows the presence, not the absence of bugs'
    

    我们也可以使用运算符来产生相同的结果:

    >>> import functools, operator
    >>> functools.reduce(operator.add, L)
    'Testing shows the presence, not the absence of bugs'
    

    内置的reduce还允许在序列中的项目之前放置一个可选的第三个参数,以作为序列为空时的默认结果。

  • 相关阅读:
    SA(后缀数组)专题总结
    LCT总结
    多项式全家桶
    fft.ntt,生成函数,各种数和各种反演
    P3939 数颜色
    P1879 [USACO06NOV]玉米田Corn Fields
    主席树模板
    P2633 Count on a tree
    P1972 [SDOI2009]HH的项链
    数论
  • 原文地址:https://www.cnblogs.com/everfight/p/map_reduce_filter.html
Copyright © 2011-2022 走看看