当我们拿到清单的总和时,我们指定了一台加固器(memo
),然后通过清单行走,将双功能“x+y”应用到每个要素和加压器。 从程序上看,情况如下:
def mySum(list):
memo = 0
for e in list:
memo = memo + e
return memo
这是一种共同模式,对除提取钱以外的东西有用——我们可以将其概括为任何双亲功能,我们把这种功能作为参数供应,并且让打电话者具体说明初步价值。 这使我们有了以下功能:reduce
,、 / . /code>, 或inject
>:<>?
def myReduce(function, list, initial):
memo = initial
for e in list:
memo = function(memo, e)
return memo
def mySum(list):
return myReduce(lambda memo, e: memo + e, list, 0)
在Zahur 2,reduce <>/code>是建构功能,但在Avry 3中,该功能被移至functools
。 模块:
from functools import reduce
我们可以根据我们作为第一种论点所提供的职能,用<条码>减去<>>>>>的冷却。 如果我们把“总”改为“清单分类”,将“零”改为“豁免清单”。 职能:
def myCopy(list):
return reduce(lambda memo, e: memo + [e], list, [])
myCopy(range(10))
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
如果我们添加一个<代码>transform功能,作为另一个参数,以copy
,并在设计之前适用该功能,我们就获得<编码>> 地图<>。
def myMap(transform, list):
return reduce(lambda memo, e: memo + [transform(e)], list, [])
myMap(lambda x: x*2, range(10))
> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
如果我们添加一个<代码>predicate功能,该功能以e
为参数,并回归一个细菌,并用该代码来决定是否加以压缩,我们就获得<编码>filter:
def myFilter(predicate, list):
return reduce(lambda memo, e: memo + [e] if predicate(e) else memo, list, [])
myFilter(lambda x: x%2==0, range(10))
> [0, 2, 4, 6, 8]
。 由于<代码>reduce<>/code>,因此没有相应的核对表。 只需要回到一份清单(见sum<>/code>,较早时,这段话也是为了作为内在功能提供。
由此可见,对于计算一个总合而言,<代码>reduce<>/code>的造物能力恰恰是我们想要的,或许是解决这一问题的最合法途径,尽管其声誉(连同lambda
)是非致命的shi。 缩略语 留在其原有价值的印本上,其编号为 reductions
或scanl
<>>> >?
def reductions(function, list, initial):
return reduce(lambda memo, e: memo + [function(memo[-1], e)], list, [initial])
因此,我们现在可以确定:
def running_sum(list):
first, rest = list[0], list[1:]
return reductions(lambda memo, e: memo + e, rest, first)
running_sum(range(10))
> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
虽然从概念上说,这种准确的做法在实际中与沙捞越差。 由于Zahur slist.append()
> 变更了已经制定但又未返回的一览表,我们可以有效地将清单用在Mlambda,而必须使用+
。 这份新的清单与迄今累积清单(即O(n)业务)的时间相称。 由于我们已在O(n)for
loop of reduce/code>内重新编号。 当我们这样做时,总体时间复杂性会波及O(n2)。
以下述语文分发:。
class Array
def reductions(initial, &proc)
self.reduce [initial] do |memo, e|
memo.push proc.call(memo.last, e)
end
end
end
def running_sum(enumerable)
first, rest = enumerable.first, enumerable.drop(1)
rest.reductions(first, &:+)
end
running_sum (0...10)
> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
同样,在《 Java本:<><><>>><>>>>>>>>>>>>>> > >-> ><>>>> >> > >> > > > >>>> >>>>> > > > >------------------------------------------------------------------>-----------------------------------------------------------------------------------------------------------------
function reductions(array, callback, initial) {
return array.reduce(function(memo, e) {
memo.push(callback(memo[memo.length - 1], e));
return memo;
}, [initial]);
}
function runningSum(array) {
var first = array[0], rest = array.slice(1);
return reductions(rest, function(memo, e) {
return x + y;
}, first);
}
function range(start, end) {
return(Array.apply(null, Array(end-start)).map(function(e, i) {
return start + i;
}
}
runningSum(range(0, 10));
> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
因此,我们如何能够在保留一个<条码>削减<>/条码>功能的概念简单化的同时解决这一问题,而我们只是通过<条码>lambda x, y:x+ y,以便建立总合功能? 请在程序上重写<条码>削减条码>。 我们可以确定 问题,虽然我们当时赞成,但事先公布结果清单,以避免ap裂[3]:
def reductions(function, list, initial):
result = [None] * len(list)
result[0] = initial
for i in range(len(list)):
result[i] = function(result[i-1], list[i])
return result
def running_sum(list):
first, rest = list[0], list[1:]
return reductions(lambda memo, e: memo + e, rest, first)
running_sum(range(0,10))
> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
这是我最热点:O(n)业绩,优化的《程序法》被贴上有意义的名称,在你今后需要写一份把中间价值积累起来的职能时可以重新使用。
- The names
reduce
/reductions
come from the LISP tradition, foldl
/scanl
from the ML tradition, and inject
from the Smalltalk tradition.
- Python s
List
and Ruby s Array
are both implementations of an automatically resizing data structure known as a "dynamic array" (or std::vector
in C++). JavaScript s Array
is a little more baroque, but behaves identically provided you don t assign to out of bounds indices or mutate Array.length
.
- The dynamic array that forms the backing store of the list in the Python runtime will resize itself every time the list s length crosses a power of two. Resizing a list means allocating a new list on the heap of twice the size of the old one, copying the contents of the old list into the new one, and returning the old list s memory to the system. This is an O(n) operation, but because it happens less and less frequently as the list grows larger and larger, the time complexity of appending to a list works out to O(1) in the average case. However, the "hole" left by the old list can sometimes be difficult to recycle, depending on its position in the heap. Even with garbage collection and a robust memory allocator, pre-allocating an array of known size can save the underlying systems some work. In an embedded environment without the benefit of an OS, this kind of micro-management becomes very important.