Python 使用map/reduce反转列表
我正在学习函数式编程的概念并尝试问题练习。 演习,, 使用map/reduce反转列表。 我的解决方案:Python 使用map/reduce反转列表,python,dictionary,functional-programming,reduce,Python,Dictionary,Functional Programming,Reduce,我正在学习函数式编程的概念并尝试问题练习。 演习,, 使用map/reduce反转列表。 我的解决方案: lists = [ 1, 2, 3, 5 ,6] def tree_reverse(lists): return reduce(lambda a, x: a + [a.insert(0,x)], lists, []) print tree_reverse(lists) 输出: [6, 5, 3, 2, 1, None, None, None, None, None] 我不明白
lists = [ 1, 2, 3, 5 ,6]
def tree_reverse(lists):
return reduce(lambda a, x: a + [a.insert(0,x)], lists, [])
print tree_reverse(lists)
输出:
[6, 5, 3, 2, 1, None, None, None, None, None]
我不明白为什么列表中的元素数等于零
编辑:扩展嵌套列表案例的问题
lists = [ 1 ,2 ,3 , [5,6,7], 8, [9, 0, 1 ,4 ]]
reduce操作将
None
追加到列表a
的末尾,因为a.insert(0,x)
将返回None
因此,您在原地修改列表a
,但同时附加None
值
如果您将reduce
操作重写为使用for
循环,它将如下所示:
def reverse_list(lists):
r = []
for x in lists:
val = r.insert(0,x)
r = r + [val] # val (the return value of r.insert) is None
return r
reduce操作将
None
追加到列表a
的末尾,因为a.insert(0,x)
将返回None
因此,您在原地修改列表a
,但同时附加None
值
如果您将reduce
操作重写为使用for
循环,它将如下所示:
def reverse_list(lists):
r = []
for x in lists:
val = r.insert(0,x)
r = r + [val] # val (the return value of r.insert) is None
return r
如果是嵌套列表。我张贴答案以供参考
lists = [ 1 ,2 ,3 , [5,6,7], 8, [9, 0, 1 ,4 ]]
def tree_reverse(lists):
return reduce(lambda a, x: ( map(tree_reverse, [x]) if isinstance(x,list) else [x] ) + a , lists , [] )
print tree_reverse(lists)
输出:
[[4, 1, 0, 9], 8, [7, 6, 5], 3, 2, 1]
如果是嵌套列表。我张贴答案以供参考
lists = [ 1 ,2 ,3 , [5,6,7], 8, [9, 0, 1 ,4 ]]
def tree_reverse(lists):
return reduce(lambda a, x: ( map(tree_reverse, [x]) if isinstance(x,list) else [x] ) + a , lists , [] )
print tree_reverse(lists)
输出:
[[4, 1, 0, 9], 8, [7, 6, 5], 3, 2, 1]
起初,我对Python的了解还不够好,但当您将问题标记为“函数式编程”并表示希望了解函数式编程的一般知识时,我想对您的问题给出一些一般性的解释。 首先,您应该重新思考
map
和reduce
操作的作用以及它们的期望。让我们从map
函数开始
列表的map
函数(在函数式编程中,不是只有一个映射,每个泛型类型都有一个映射)对每个参数执行一个函数。该函数可以对单个参数进行操作并对其进行转换。此转换的结果将转换为一个新列表。一个重要的注意事项是,传递给map
的函数只能看到一个元素,因此不能使用map
本身来转换整个列表。您只能转换列表中的每个元素。但是改变顺序需要一个列表中至少有两个元素,并且一个映射只能得到一个元素。这就是为什么反向逻辑不能在map
中,并且必须是reduce
操作的一部分
另一方面,reduce
函数需要一个函数,该函数接受两个相同类型的项,并返回一个相同类型的项。例如,reduce函数可以采用“+”函数。“+”是一个函数,它接受两个int
,并返回一个新的int
。签名基本上是int+int=int
。reduce的本质是把两个东西合并成一个新的项目。例如,如果您有一个更复杂的类“Foo”,那么您必须提供函数来减少签名Foo*Foo->Foo
。意思是将一个Foo
作为第一个和第二个参数,并返回一个新的Foo
注意reduce
如何使用该功能也很重要。假设列表顶部有一个[1,2,3,4,5]
,假设有一个累加器函数
,该函数取两个int
,将它们相加。你能想到的是,接下来会发生什么
reduce
函数接受列表的前两个参数(本例中为1和2)[1,2,3,4,5] -> 1 + 2 = 3
[3,3,4,5] -> 3 + 3 = 6
[6,4,5] -> 6 + 4 = 10
[10,5] -> 10 + 5 = 15
[15] -> Return just "15". Not a "[15]"
实际上,内部流程通常会有一点不同。但这是一个你可以想象会发生什么的过程。请务必注意,您从不修改列表。您总是在该过程中创建新列表。另一个重要的注意事项。在reduce
功能的末尾,您有一个单个项目的列表。但是reduce
函数不会返回整个列表。它只返回单个元素。因此得到15
一个int
。您不会得到包含15
的单个项目的列表。Reduce将只返回单个元素。不管是什么。另一种思考方式。您总是能准确地返回累加器函数的类型。如果传递一个接受两个int
的累加器函数
,则添加它们并返回一个新的int
。reduce函数还将返回一个int
。如果传递一个累加器函数
,该函数接受两个Foo
类并返回一个新的Foo
。reduce
函数还将返回一个Foo
作为其结果。reduce
的返回类型始终与累加器函数的类型相同
现在,让我们把所有这些碎片放在一起。目标是扭转一个列表。第一件重要的事情是。您的结果类型将是一个列表
。这也意味着传递到reduce
的函数也必须返回列表。但由于输入和输出总是一样的。现在必须提供一个累加器函数
,该函数接受两个列表,并返回一个新列表
但现在让我们退一步。如果您直接使用列表“[1,2,3,4,5]”作为输入来减少,会发生什么?简单的回答是,它不会起作用reduce
将接受列表中的两个参数。但是你有一个int的列表。但是你的累加器函数
需要两个列表而不是两个int。来解决这个问题
[[1],[2],[3],[4],[5]] -> [2] ++ [1] = [2,1]
[[2,1],[3],[4],[5]] -> [3] ++ [2,1] = [3,2,1]
[[3,2,1],[4],[5]] -> [4] ++ [3,2,1] = [4,3,2,1]
[[4,3,2,1],[5]] -> [5] ++ [4,3,2,1] = [5,4,3,2,1]
[[5,4,3,2,1]] -> Return first element [5,4,3,2,1]
def tree_reverse(lists):
return tree_reverse(lists[1:]) + [lists[0]] if lists else []
reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = reverse' xs ++ [x]