zoukankan      html  css  js  c++  java
  • python的map、reduce和filter(过滤器)函数(廖雪峰老师python基础)

    1、map

    语法:

    map(func,Iterable)

    map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

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

    map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

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

    2、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

    当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。
    但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:
    >>> from functools import reduce
    >>> def fn(x, y):
    ... return x * 10 + y
    ...
    >>> reduce(fn, [1, 3, 5, 7, 9])
    13579

    这个例子本身没多大用处,但是,如果考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:
    >>> from functools import reduce
    >>> def fn(x, y):
    ... return x * 10 + y
    ...
    >>> def char2num(s):
    ... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    ...
    >>> reduce(fn, map(char2num, '13579'))
    13579
    整理成一个str2int的函数就是:
    from functools import reduce
    def str2int(s):
      def fn(x, y):
        return x * 10 + y
      def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
      return reduce(fn, map(char2num, s))
    还可以用lambda函数进一步简化成:

    from functools import reduce
    def str2int(s):
      # def fn(x, y):
      # return x * 10 + y
      def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
      # return reduce(fn, map(char2num, s))
      return reduce(lambda x, y: x * 10 + y, map(char2num, s))

    也就是说,假设Python没有提供int()函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码!

    3、filter过滤器

    Python内建的filter()函数用于过滤序列。
    和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。


    例如,在一个list中,删掉偶数,只保留奇数,可以这么写:
    def is_odd(n):
      return n % 2 == 1
    list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
    # 结果: [1, 5, 9, 15]
    把一个序列中的空字符串删掉,可以这么写:
    def not_empty(s):
    return s and s.strip()
    list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
    # 结果: ['A', 'B', 'C']
    可见用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。
    注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

    问题:求素数

    计算素数的一个方法是埃氏筛法,它的算法理解起来非常简单:
    首先,列出从2开始的所有自然数,构造一个序列:
    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
    取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
    3, , 5, , 7, , 9, , 11, , 13, , 15, , 17, , 19, , ...
    取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
    5, , 7, , , , 11, , 13, , , , 17, , 19, , ...
    取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
    7, , , , 11, , 13, , , , 17, , 19, , ...
    不断筛下去,就可以得到所有的素数。


    用Python来实现这个算法,可以先构造一个从3开始的奇数序列:
    def _odd_iter():
      n = 1
      while True:
        n = n + 2
        yield n
    注意这是一个生成器,并且是一个无限序列。
    然后定义一个筛选函数:
    def _not_divisible(n):
      return lambda x: x % n > 0
    最后,定义一个生成器,不断返回下一个素数:
    def primes():
      yield 2
    it = _odd_iter() # 初始序列
    while True:
      n = next(it) # 返回序列的第一个数
    yield n
    it = filter(_not_divisible(n), it) # 构造新序列

    这个生成器先返回第一个素数2,然后,利用filter()不断产生筛选后的新的序列。
    由于primes()也是一个无限序列,所以调用时需要设置一个退出循环的条件:

    # 打印1000以内的素数:
    for n in primes():
      if n < 1000:
      print(n)
    else:
      break
    注意到Iterator是惰性计算的序列,所以我们可以用Python表示“全体自然数”,“全体素数”这样的序列,而代码非常简洁。

    总结:

    filter()的作用是从一个序列中筛出符合条件的元素。由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。

    明月装饰了你的窗子,你装饰了他的梦。
  • 相关阅读:
    INVALID_STATE_ERR: DOM Exception 11
    测试用户的网络环境
    CentOS修改IP、DNS、网关
    读《结网》
    命名函数表达式
    JavaScript中的编码函数
    linux下C程序printf没有立即输出的问题及我的Makefile文件
    学习使用vimperator
    thinkpad e40 安装 nvidia显卡驱动之后
    fedora:在命令行下删除文件到回收站
  • 原文地址:https://www.cnblogs.com/zkkysqs/p/9398947.html
Copyright © 2011-2022 走看看