使用地图/缩小的反向列表

s00*_*007 1 python reduce dictionary functional-programming

我正在学习函数式编程的概念并尝试问题练习。一个练习,使用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)
Run Code Online (Sandbox Code Playgroud)

输出:

[6, 5, 3, 2, 1, None, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

我不明白为什么列表中的元素数等于None。

编辑:扩展问题的嵌套列表的情况。

 lists = [ 1 ,2 ,3 , [5,6,7], 8, [9, 0, 1 ,4 ]]
Run Code Online (Sandbox Code Playgroud)

Dav*_*aab 5

刚开始,我对Python不够了解,但是当您将问题标记为“函数编程”时,您说过您想对函数式编程进行一般性的学习,我想对问题进行一些一般性的解释。首先,您应该重新考虑the mapreduce操作的作用以及他们的期望。让我们从map函数开始。

一个map为列表功能(在函数式编程,你不只有一个地图,你有一张地图,每通用型)执行对每一个参数的函数。该函数可以对该单个参数进行操作并对其进行转换。转换的结果将变成一个新列表。一个重要的注意事项是,传递给该函数的函数map只能看到一个元素,因此您不能使用map自身来转换整个列表。您只能变换列表的每个元素。但是更改顺序需要这样的想法:列表中至少要包含两个元素,而地图只能获得一个元素。这就是为什么反向逻辑不能插入map并且必须作为reduce操作的一部分的原因。

reduce另一方面,该函数期望一个函数接受具有相同类型的两个事物,并返回相同类型的单个项目。例如,reduce函数可以采用“ +”函数。“ +”是一个需要两个int并返回一个new 的函数int。签名基本上是int + int = int。reduce的本质是将两件事变成一个单一的新项目。例如,如果您拥有诸如“ Foo”类之类的更复杂的东西,那么您必须提供的功能将减少具有签名的需求Foo * Foo -> Foo。含义将a Foo作为第一个和第二个参数,并返回一个new Foo

同样重要的是要注意如何reduce使用该功能。假设您的列表[1,2,3,4,5]位于顶部,假设您的列表accumulator function中有两个int,它们只是将它们加在一起。您可以想到的是以下内容。

  1. reduce函数采用列表的前两个参数(在这种情况下为1和2)
  2. 将那些传递给accumulator function(1 + 2 = 3)
  3. 并用结果替换列表中的两个参数。[3,3,4,5]
  4. 返回1)并重复该过程,直到您的列表中只有一个项目为止
  5. 退货

所以您可以想象发生了以下情况

[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]"
Run Code Online (Sandbox Code Playgroud)

实际上,内部流程通常会有所不同。但这是您可以想象发生的过程。重要的是要注意,您永远不要修改列表。您始终在该过程中创建新列表。另一个重要说明。在该reduce功能的最后,您将获得一个单项列表。但是该reduce函数不会返回整个列表。它仅返回单个元素。所以,你得到15int结果。您找不到包含的单个项目的列表15。Reduce将仅返回该单个元素。不管是什么。思考的另一种方式。您总是会得到准确的类型accumulator function。如果您通过accumulator function,则需要两个int将它们相加并返回一个新值int。您的reduce函数还将返回一个int。如果您通过accumulator function,则需要两个Foo类并返回新的Foo。您的reduce函数还将返回a Foo作为其结果。的返回类型reduce始终与的类型相同accumulator function

现在,让我们将所有这些片段放在一起。目标是反转列表。首先重要的是。您的结果类型将为list。这也意味着传递给您的函数reduce还必须返回list。但是由于输入始终与输出相同。现在,您必须提供一个accumulator function包含两个列表并返回一个新列表的。

但是现在让我们退后一步。如果您直接使用列表“ [1,2,3,4,5]”作为减少的输入会发生什么?简短的答案是,它将不起作用。reduce将采用您列表的两个参数。但是您拥有的是一个int列表。但是您accumulator function期望两个列表而不是两个int。为了解决该问题,您现在可以尝试将列表中的每个元素转换为自己的列表。那么,如何转换列表中的每个元素?对!用map!因此,您需要执行以下操作。您首先将列表映射到列表列表中。

[1,2,3,4,5] -> [[1],[2],[3],[4],[5]]
Run Code Online (Sandbox Code Playgroud)

现在,reduce函数将获得第一个列表的前两个元素。这意味着您现在有了一个get [1][2]作为其参数的累加器函数。两个单独的列表。但是您的累加器函数必须返回一个新列表。如果不清楚,只需提醒累加器函数采取什么并返回。

int, int    -> int
float,float -> float
Foo,Foo     -> Foo
list,list   -> list
Run Code Online (Sandbox Code Playgroud)

因此,您现在要做的就是将这两个列表合并为一个新列表。换句话说,您必须追加/合并这两个列表。我不确切知道如何在Python中合并两个列表,让我们假设此处的操作为“ ++”。因此,如果仅合并第一个参数和第二个参数,将无法获得所需的结果。

[[1],[2],[3],[4],[5]] -> [1]       ++ [2] = [1,2]
[[1,2],[3],[4],[5]]   -> [1,2]     ++ [3] = [1,2,3]
[[1,2,3],[4],[5]]     -> [1,2,3]   ++ [4] = [1,2,3,4]
[[1,2,3,4],[5]]       -> [1,2,3,4] ++ [5] = [1,2,3,4,5]
[[1,2,3,4,5]]         -> Return first element [1,2,3,4,5]
Run Code Online (Sandbox Code Playgroud)

因此,您要做的是将第二个参数与第一个参数结合起来。

[[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]
Run Code Online (Sandbox Code Playgroud)

现在,您得到的是您的反向列表。所以你要做的

  1. 将每个元素映射到列表。所以你得到一个清单清单
  2. 使用reduce将列表的每个列表按相反的顺序连接到新列表中。

例如,在F#中,整个代码将如下所示。

[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]"
Run Code Online (Sandbox Code Playgroud)

我认为您应该可以将其转换为Python。进一步通知。在功能编程中,先执行“映射”,然后执行“连续”操作(不反向),也称为“绑定”。