使用python map和其他功能工具

127 python dictionary functional-programming

这非常难以理解,但我正在尝试学习/理解python中的函数式编程.以下代码:

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo, bar):
    print foo, bar

map(maptest, foos, bars)
Run Code Online (Sandbox Code Playgroud)

生产:

1.0 1
2.0 2
3.0 3
4.0 None
5.0 None
Run Code Online (Sandbox Code Playgroud)

问:有没有办法在python中使用map或任何其他功能工具来生成以下没有循环等.

1.0 [1,2,3]
2.0 [1,2,3]
3.0 [1,2,3]
4.0 [1,2,3]
5.0 [1,2,3]
Run Code Online (Sandbox Code Playgroud)

正如附注所示,如果foo和bar之间存在依赖关系,实现将如何变化.例如

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]
Run Code Online (Sandbox Code Playgroud)

并打印:

1.0 [2,3,4,5]
2.0 [1,3,4,5]
3.0 [1,2,4,5]
...
Run Code Online (Sandbox Code Playgroud)

PS:我知道如何使用if,循环和/或生成器天真地做,但我想学习如何使用功能工具实现相同的功能.是仅仅在maptest中添加if语句或在maptest内部将另一个过滤器映射应用于条形图的情况?

Joh*_*uhy 194

您熟悉其他功能语言吗?即,您是否正在尝试学习python如何进行函数式编程,或者您是否正在尝试学习函数式编程并使用python作为工具?

另外,你了解列表理解吗?

map(f, sequence)
Run Code Online (Sandbox Code Playgroud)

直接等价于(*)到:

[f(x) for x in sequence]
Run Code Online (Sandbox Code Playgroud)

事实上,我认为map()曾经计划从python 3.0中删除多余(没有发生).

map(f, sequence1, sequence2)
Run Code Online (Sandbox Code Playgroud)

大致相当于:

[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]
Run Code Online (Sandbox Code Playgroud)

(它处理序列长度不同的情况有所不同.如您所见,map()当其中一个序列用完时填充无,而zip()当最短序列停止时则填写)

因此,要解决您的具体问题,您需要尝试生成结果:

foos[0], bars
foos[1], bars
foos[2], bars
# etc.
Run Code Online (Sandbox Code Playgroud)

您可以通过编写一个带有单个参数并打印它的函数来执行此操作,然后执行以下操作:

def maptest(x):
     print x, bars
map(maptest, foos)
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建一个如下所示的列表:

[bars, bars, bars, ] # etc.
Run Code Online (Sandbox Code Playgroud)

并使用您原来的maptest:

def maptest(x, y):
    print x, y
Run Code Online (Sandbox Code Playgroud)

一种方法是事先明确地建立列表:

barses = [bars] * len(foos)
map(maptest, foos, barses)
Run Code Online (Sandbox Code Playgroud)

或者,您可以拉入itertools模块. itertools包含许多聪明的函数,可以帮助您在python中进行函数式的惰性求值编程.在这种情况下,我们希望itertools.repeat,当您迭代它时,它将无限期地输出其参数.最后一个事实意味着,如果你这样做:

map(maptest, foos, itertools.repeat(bars))
Run Code Online (Sandbox Code Playgroud)

你将得到无穷无尽的输出,因为map()只要其中一个参数仍在产生输出就会继续.但是,itertools.imap就像map(),但是一旦最短的可迭代停止就停止.

itertools.imap(maptest, foos, itertools.repeat(bars))
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :-)

(*)它在python 3.0中有点不同.在那里,map()基本上返回一个生成器表达式.


sth*_*sth 54

最简单的方法是不要bars通过不同的功能,而是直接从maptest以下方式访问它:

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo):
    print foo, bars

map(maptest, foos)
Run Code Online (Sandbox Code Playgroud)

使用原始maptest函数,您还可以使用lambda函数map:

map((lambda foo: maptest(foo, bars)), foos)
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案直接违背了OP想要尝试学习的函数式编程原理.函数式编程的一个基本规则是每次调用具有相同参数的函数时,总是得到相同的输出.这避免了通过具有全局状态引入的vipers嵌套错误.由于maptest取决于条形的外部定义,因此该原则被打破. (59认同)
  • 亲爱的堆栈溢出,因为你想关闭问题并且适度地重,你为什么不将这个问题取消标记为答案并将正确的答案标记为答案?问候,我们. (3认同)

Jas*_*ker 30

这是您正在寻找的解决方案:

>>> foos = [1.0, 2.0, 3.0, 4.0, 5.0]
>>> bars = [1, 2, 3]
>>> [(x, bars) for x in foos]
[(1.0, [1, 2, 3]), (2.0, [1, 2, 3]), (3.0, [1, 2, 3]), (4.0, [1, 2, 3]), (5.0, [
1, 2, 3])]
Run Code Online (Sandbox Code Playgroud)

我建议使用list comprehension([(x, bars) for x in foos]部分)而不是使用map,因为它避免了每次迭代时函数调用的开销(这可能非常重要).如果你只是想在for循环中使用它,你将通过使用生成器理解获得更好的速度:

>>> y = ((x, bars) for x in foos)
>>> for z in y:
...     print z
...
(1.0, [1, 2, 3])
(2.0, [1, 2, 3])
(3.0, [1, 2, 3])
(4.0, [1, 2, 3])
(5.0, [1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

不同之处在于生成器理解是延迟加载的.

更新 回应此评论:

当然你知道,你没有复制条,所有条目都是相同的条形列表.因此,如果您修改其中任何一个(包括原始条),则修改所有这些.

我想这是一个有效的观点.我能想到有两种解决方案.最有效的可能是这样的:

tbars = tuple(bars)
[(x, tbars) for x in foos]
Run Code Online (Sandbox Code Playgroud)

由于元组是不可变的,这将阻止通过此列表理解的结果修改条形(或者如果你去那条路线则生成器理解).如果您确实需要修改每个结果,可以执行以下操作:

from copy import copy
[(x, copy(bars)) for x in foos]
Run Code Online (Sandbox Code Playgroud)

但是,就内存使用和速度而言,这可能有点贵,所以除非你真的需要添加它们,否则我建议不要这样做.


Dus*_*tin 20

函数式编程是关于创建无副作用的代码.

map是一个功能列表转换抽象.你使用它来获取一些东西并将其转换为其他东西的序列.

您正在尝试将其用作迭代器.不要那样做.:)

以下是如何使用map构建所需列表的示例.有更短的解决方案(我只是使用理解),但这将有助于您了解哪些地图做得更好:

def my_transform_function(input):
    return [input, [1, 2, 3]]

new_list = map(my_transform, input_list)
Run Code Online (Sandbox Code Playgroud)

请注意,此时您只进行了数据操作.现在你可以打印出来了:

for n,l in new_list:
    print n, ll
Run Code Online (Sandbox Code Playgroud)

- 我不确定你的意思是'没有循环'.fp不是关于避免循环(你不能检查列表中的每个项目而不访问每个项目).这是为了避免副作用,从而减少错误.


Rob*_*let 12

>>> from itertools import repeat
>>> for foo, bars in zip(foos, repeat(bars)):
...     print foo, bars
... 
1.0 [1, 2, 3]
2.0 [1, 2, 3]
3.0 [1, 2, 3]
4.0 [1, 2, 3]
5.0 [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 11

import itertools

foos=[1.0, 2.0, 3.0, 4.0, 5.0]
bars=[1, 2, 3]

print zip(foos, itertools.cycle([bars]))
Run Code Online (Sandbox Code Playgroud)


Nik*_*iah 6

以下是该map(function, *sequences)函数的参数概述:

  • function 是你的功能的名称.
  • sequences是任何数量的序列,通常是列表或元组. map同时迭代它们并给出当前值function.这就是为什么序列的数量应该等于你的函数的参数数量.

听起来你正试图迭代某些function参数,但保持其他参数不变,不幸的map是不支持.我发现了一个旧的提议,要将这样的功能添加到Python中,但是地图构造是如此干净和完善,我怀疑这样的东西将会被实现.

正如其他人所建议的那样,使用全局变量或列表推导等变通方法.