📜  带有示例的Python中的map(),filter()和reduce()

📅  最后修改于: 2020-08-24 07:13:02             🧑  作者: Mango

介绍

map()filter()reduce()功能带来一点函数式编程到Python的。所有这三个都是便利功能,可以用列表推导或循环代替,但可以为某些问题提供更优雅,更简捷的方法。

在继续之前,我们将介绍一些您应该熟悉的内容,然后再介绍上述方法:

什么是匿名函数/方法或lambda?

匿名方法是没有名称的方法,即不像我们使用定义方法时那样绑定到标识符def method:

注意:尽管大多数人可以互换使用术语“匿名函数”“ lambda函数”,但它们并不相同。发生此错误的原因是,在大多数编程语言中,lambda 匿名的,而所有匿名函数都是 lambda。在Python中也是如此。因此,我们将不在本文中进一步讨论这种区别。

lambda函数(或lambda运算符)的语法是什么?

lambda arguments: expression

将lambda视为没有名称的单行方法。它们的工作原理几乎与Python中的任何其他方法相同,例如:

def add(x,y):
	return x + y

可以翻译为:

lambda x, y: x + y

Lambda与普通的Python方法不同,因为它们只能具有一个表达式,不能包含任何语句,并且其返回类型是一个function对象。因此,上面的代码行不完全返回值,x + y而是返回计算的函数x + y

为什么lambda表达式相关的map()filter()reduce()

所有这三种方法都将function对象作为第一个参数。该function对象可以是带有名称的预定义方法(如def add(x,y))。

尽管传递给map()filter()和的函数通常reduce()只是一次使用,所以通常没有必要定义可引用的函数。

为了避免定义为不同的新功能map()filter()reduce()需求-一个更优雅的解决办法是使用短,一次性的,匿名的功能,你将只使用一次,永无-拉姆达。

map()函数

map()函数遍历给定iterable中的所有项目,并function在每个项目上执行作为参数传递的we。

语法为:

map(function, iterable(s))

传递function我们要使用的对象后,我们可以传递任意数量的可迭代对象:

# Without using lambdas
def starts_with_A(s):
    return s[0] == "A"

fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(starts_with_A, fruit)

print(list(map_object))

此代码将导致:

[True, False, False, True, False]

如我们所见,我们最终得到一个新列表,其中对list中的starts_with_A()每个元素都对其功能进行了评估fruit。此功能的结果被顺序添加到列表中。

一种更精确的方法是使用lambda:

fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(lambda s: s[0] == "A", fruit)

print(list(map_object))

我们得到相同的输出:

[True, False, False, True, False]

注意:您可能已经注意到,我们已经强制map_object转换为列表以打印每个元素的值。我们这样做是因为调用print()列表将打印元素的实际值。调用print()map_object会打印值的内存地址来代替。

map()函数返回map_object一个可迭代的类型,我们也可以打印出如下结果:

for value in map_object:
    print(value)

如果您希望该map()函数返回一个列表,则可以在调用该函数时对其进行强制转换:

result_list = list(map(lambda s: s[0] == "A", fruit))

filter()函数

与相似map()filter()接受一个function对象和一个可迭代对象并创建一个新列表。

顾名思义,filter()形成一个新列表,其中仅包含满足特定条件的元素,即function我们传递的return True

语法为:

filter(function, iterable(s))

使用前面的示例,我们可以看到新列表仅包含该starts_with_A()函数返回的元素True

# Without using lambdas
def starts_with_A(s):
    return s[0] == "A"

fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(starts_with_A, fruit)

print(list(filter_object))

运行以下代码将得到较短的列表:

['Apple', 'Apricot']

或者,使用lambda重写:

fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(lambda s: s[0] == "A", fruit)

print(list(filter_object))

打印给我们相同的输出:

['Apple', 'Apricot']

reduce()函数

reduce()工作原理与map()和不同filter()。它不会根据function我们传递的和可迭代返回一个新列表。而是返回一个值。

此外,在Python 3中,reduce()它不再是内置函数,可以在functools模块中找到。

语法为:

reduce(function, sequence[, initial])

reduce()通过调用function序列中前两项传递的we来工作。所返回的结果将在下一个(在本例中为第三个)元素的function另一个调用中function使用。

重复此过程,直到我们遍历了序列中的所有元素。

可选参数initial(如果存在)在此“循环”的开始处使用,并在第一次调用中使用第一个元素function。在某种程度上,如果提供的话,该initial元素是第一个元素之前的第0个元素。

reduce()map()和更难理解filter()。因此,让我们看一个逐步的示例:

  1. 我们从一个列表开始,[2, 4, 7, 3]然后将add(x, y)函数传递到reduce()该列表的旁边,而没有initial
  2. reduce()调用add(2, 4)add()返回6
  3. reduce()调用add(6, 7)(上次调用的结果add()和列表中下一个元素作为参数的结果),并add()返回13
  4. reduce()调用add(13, 3)add()返回16
  5. 由于序列中没有剩余元素,因此reduce()返回16

如果我们提供了一个initial值,唯一的不同是额外的步骤-1.5。在第2步中哪里reduce()调用add(initial, 2)和使用该返回值。

让我们继续使用该reduce()函数:

from functools import reduce

def add(x, y):
    return x + y

list = [2, 4, 7, 3]
print(reduce(add, list))

运行此代码将产生:

16

同样,这可以使用lambdas编写:

from functools import reduce

list = [2, 4, 7, 3]
print(reduce(lambda x, y: x + y, list))
print("With an initial value: " + str(reduce(lambda x, y: x + y, list, 10)))

该代码将导致:

16
With an initial value: 26

结论

如前所述,这些功能是便利功能。它们在那里,因此您可以避免编写更多繁琐的代码,但避免同时使用它们和lambda表达式。

不要强迫使用这些工具,因为“您可以”,因为它通常会导致难以维护的难以理解的代码。仅当您完全清楚函数或lambda表达式后,才使用它们。

如果您发现自己在努力将必要的逻辑装入一个map()函数或一个lambda表达式中,则最好编写稍长的for-loop / defined方法,并避免以后不必要的混乱。