Хобрук: Ваш путь к мастерству в программировании

Pythonic уменьшить с накоплением и произвольной лямбда-функцией?

Каким будет Pythonic способ выполнения сокращения с накоплением?

Например, возьмем Reduce() пользователя R. . Учитывая список и произвольную лямбда-функцию, он позволяет получить вектор накопленных результатов, а не только окончательный результат, установив accumulate=T. Примером этого с простым умножением в качестве лямбда-функции может быть (взято из этого ответа):

Reduce(`*`, x=list(5,4,3,2), accumulate=TRUE)
# [1]   5  20  60 120

Важно, чтобы можно было использовать произвольную лямбда-функцию (например, lambda x, y: ...), поэтому решения, которые позволяют, например, только использование суммы, умножения или чего-то еще не поможет. Я не смог придумать решение Pythonic, чтобы сделать это, например. itertools или functools, но способ есть. И хотя есть множество других вопросов и ответов о сокращении и особенно о накоплении с помощью Python, я пока не нашел общего ответа.

Не-Pythonic пример, использующий цикл для выполнения накопленного сокращения с произвольной лямбда-функцией, может выглядеть так:

# the source list
l = [0.5, 0.9, 0.8, 0.1, 0.1, 0.9]
# the lambda function for aggregation can be arbitrary
# this one is just made up for the example
func = lambda x, y: x * 0.65 + y * 0.35 

# the accumulated reduce:
# a) the target list with initializer value hardcoded
l2 = [l[0]]
# b) the loop
for i in range(1, len(l)):
    l2 += [func(
            l2[i-1],    # last value in l2
            l[i]        # new value from l   
            )]

Итак: как бы вы сделали сокращение с накоплением и произвольной лямбда-функцией в стиле Python?


Ответы:


1

В Python 3 (представлено в 3.2, возможность передачи функции добавлена ​​в 3.3) это уже реализовано в itertools.accumulate. Просто используйте это так:

from itertools import accumulate
list(accumulate([5, 4, 3, 2], lambda a, b: a*b))
# [5, 20, 60, 120]

Если вы используете более раннюю версию Python или хотите реализовать ее самостоятельно, и вы действительно хотите, чтобы любой произвольный lambda (который принимает два аргумента) работал, вы можете использовать генератор, который приведен в документации выше:

def accumulate(iterable, func=operator.add):
    'Return running totals'
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
    it = iter(iterable)
    try:
        total = next(it)
    except StopIteration:
        return
    yield total
    for element in it:
        total = func(total, element)
        yield total

Использование точно такое же, как описано выше.


Если вы используете numpy, то существует более быстрое решение, по крайней мере, для всех numpy.ufunc. К ним относятся в основном те же функции, которые предоставляет модуль стандартной библиотеки math, а затем и некоторые другие. Полный список можно найти здесь.

Каждый numpy.ufunc имеет метод accumulate, поэтому вы можете просто сделать:

import numpy as np
np.multiply.accumulate([5, 4, 3, 2])
# array([  5,  20,  60, 120])
19.02.2018
Новые материалы

Почему я, журналист, в отчаянии создал сетевое приложение B2B
Почему я, журналист, в отчаянии создал сетевое приложение B2B Итак, вот верхняя линия. Я построил OnGreentech, сеть для индустрии возобновляемых источников энергии. Если вам интересно,..

Ограниченные машины Больцмана (RBM)
Практическое руководство по обучению RBM.pdf Задний план RBM использовались в качестве генеративных моделей для многих различных типов данных, включая помеченные и немеченые. В их условной..

Обнаружение маски или без маски с YOLO😷
Это руководство по созданию пользовательской модели обнаружения объектов для обнаружения людей, носящих или не носящих маски в общественных местах, созданной с использованием YOLO v3. Модель..

Управление приборами в чистом PHP
Этот пост дополняет эти: E2e тестирование Работа с несколькими средами . Мы разработали это решение для базы данных MariaDB, оно может отличаться, если вы используете другую базу..

Неделя 1 — Кентерберийские рельсы.
Неделя 1 — Кентерберийские рельсы. So. Мы все еще живы, все еще усердно работаем и еще не пассивно-агрессивно рассылаем друг другу сообщения «за мое последнее сообщение в Slack…», поэтому, на..

Цена завтрашнего дня  — Джефф Бут
Технологический прогресс в наши дни происходит с молниеносной скоростью, и мы не в состоянии это понять. Джефф в основном говорит о влиянии технологий на экономику по всему миру. Он твердо верит..

Данные: суперсила современного бизнеса
В цифровой среде данные превратились из простого побочного продукта бизнес-операций в центральный актив, стимулирующий рост и инновации. Крейг Манди, бывший главный директор по стратегии..