代码之家  ›  专栏  ›  技术社区  ›  cs95 abhishek58g

循环地将操作数列表缩减为单个结果

  •  2
  • cs95 abhishek58g  · 技术社区  · 8 年前

    (这是另一个问题的一个重复的、自我回答的版本,因为它没有被问好。

    我有一个整数列表:

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

    我的目标是 总和 乘法 运算符依次对这些数字进行运算,以获得单个结果。

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

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

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

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

    等等。

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

    3 回复  |  直到 8 年前
        1
  •  1
  •   pault Tanjin    8 年前

    对于这种情况,这里有一种非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 如果列表的长度是偶数:

    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 接受两个输入-一个数字和一个元组。它将数字添加到元组的第一个元素,并将结果乘以第二个元素。结果是另一个数字,然后传递给下一个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
    
        2
  •  2
  •   Daniel    8 年前

    这里有一个稍微不同的答案,避免使用 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]))
    
        3
  •  1
  •   cs95 abhishek58g    8 年前

    一种解决方案是使用 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, ...))
    

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

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

    推荐文章