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阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容