2

(这是另一个问题的重新整理、自我回答的版本,由于没有很好地提出,该问题已被关闭。)

我有一个整数列表:

numbers = [1, 2, 3, 4, 5, 6]

我的目标是在这些数字上交替应用乘法运算符以获得单个结果。

例如,对于这个输入,结果是

((1 + 2) * 3 + 4) * 5 + 6

减少到 71。本质上,这可以分解为:

t1 =  1 + 2 
t2 = t1 * 3 
t3 = t2 + 4
... 

等等。

奖励:可以推广到两个以上周期性操作的解决方案将受到欢迎。

4

3 回答 3

2

这是一个略有不同的答案,避免next在 lambda 函数中使用。

import operator
from itertools import cycle

def apply_cyclic(numbers, functions):
    numbers = iter(numbers)
    functions = cycle(functions)
    result = next(numbers)
    for num, fun in zip(numbers, functions):
        result = fun(result, num)
    result num

print(apply_cyclic([1,2,3,4,5,6], [operator.add, operator.mul]))
于 2018-06-25T04:21:46.983 回答
1

一种解决方案将涉及构建一个循环生成器itertools.cycle,在内部交替使用和应用每个函数functools.reduce

from itertools import cycle
from functools import reduce
import operator

fn = cycle((operator.add, operator.mul))
result = reduce(lambda x, y: next(fn)(x, y), numbers)

print(result)
71

此解决方案的优点是您可以更改 的定义fn以连续应用任意数量的运算符:

fn = cycle((operator.add, operator.mul, operator.sub, ...))

此外,当您一次只处理两个操作数时,不存在优先级问题。

注意:不支持一元运算符。

于 2018-06-25T04:09:07.133 回答
1

这是针对这种情况的非 itertools 方法。

首先想象一下,有一个版本一次functools.reduce从一个可迭代对象中获取 3 个项目。我们称这个假设函数为reduce3

如果存在,我们可以执行以下操作:

reduce3(lambda a, b, c: (a+b)*c, numbers)

如果我们要查看这个操作的中间结果,我们会得到类似的结果:

1, 2, 3, 4, 5, 6  # Initial list
9, 4, 5, 6        # Step 1
65, 6             # Step 2
(65 + 6) * ??     # Step 3

所以这几乎是我们想要的,除了在第 3 步中没有第 3 项要乘以。事实上,这将发生在任何偶数长度的列表中。1那么,如果它的长度是偶数,那么让我们将 a 添加到列表中:

if not len(numbers) % 2:
    numbers.append(1)

在此之后,第三步将是:

(65 + 6)*1

正确答案为 71。

不幸的是,这个神奇的功能并不存在。但是,我们可以修改原始列表以模仿此功能。我们只需要获取数字列表并将连续的数字对(不包括第一个元素)分组为元组。此外,如果列表是偶数长度,我们需要将元素添加1到末尾。

本质上,让我们编写一个函数preprocess()[1, 2, 3, 4, 5, 6]变成[1, (2, 3), (4, 5), (6, 1)].

def preprocess(myList):
    my_output = [myList[0], *zip(numbers[1::2], numbers[2::2])]
    if not len(myList) % 2:
        my_output.append((myList[-1], 1))
    return my_output

print(preprocess(numbers))
#[1, (2, 3), (4, 5), (6, 1)]

现在我们可以reduce处理列表:

from functools import reduce
result = reduce(lambda a, b: (a+b[0])*b[1], preprocess(numbers))
print(result)
#71

需要 2 个输入-reducer一个数字和一个元组。它将数字添加到元组的第一个元素,并将结果乘以第二个元素。结果是另一个数字,然后将其传递给下一个reduce操作。


更新

这里是一个通用的实现reduceN。由传入的函数的N长度决定,因此可以推广到任意数量的函数。

from itertools import islice  # couldn't get away from itertools this time

def reduceN(functions, iterable, initializer=None):
    it = iter(iterable)
    n = len(functions)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    elements = list(islice(it, n))
    while(elements):
        for fn, el in zip(functions, elements):
            value = fn(value, el)
        elements = list(islice(it, n))
    return value

我们可以使用它来循环应用任意数量的函数。所以原来的例子:

from operator import add, mul
numbers = [1, 2, 3, 4, 5, 6]
functions = [add, mul]
print(reduceN(functions, numbers))
#71

如果我们从 中删除最后一个元素numbers

print(reduceN(functions=functions, iterable=[1, 2, 3, 4, 5]))
#65
于 2018-06-25T20:48:10.713 回答