(这是另一个问题的重新演练的自我解答版本,由于问题不佳而被关闭。)
我有一个整数列表:
numbers = [1, 2, 3, 4, 5, 6]
我的目标是对这些数字依次依次应用 sum 和乘法运算符以获得单个结果。
例如,对于此输入,结果应为
((1 + 2) * 3 + 4) * 5 + 6
减少到71。从本质上讲,这可以细分为:
t1 = 1 + 2
t2 = t1 * 3
t3 = t2 + 4
...
,依此类推。
奖金:可以推广到两个以上周期性操作的解决方案将受到欢迎。
答案 0 :(得分:2)
这里的答案略有不同,避免在lambda函数中使用next
。
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]))
答案 1 :(得分: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, ...))
此外,当您一次只处理两个操作数时,没有优先级问题。
注意:将不支持一元运算符。
答案 2 :(得分: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步中没有要乘以的第三个项目。实际上,对于任何偶数长度的列表都会发生这种情况。好吧,如果长度为偶数,只需在列表中附加一个1
:
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
reducer
接受2个输入-一个数字和一个元组。它将数字加到元组的第一个元素,然后将结果乘以第二个。结果是另一个数字,然后将其传递到下一个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