Сведения о вопросе

DUNKER

08:45, 27th August, 2020

Теги

Полезный код, который использует reduce()?

Просмотров: 573   Ответов: 24

Есть ли у кого-нибудь здесь полезный код, который использует функцию reduce() в python? Существует ли какой-либо код, отличный от обычных + и*, которые мы видим в примерах?

Обратитесь к судьбе reduce() в Python 3000 по GvR



  Сведения об ответе

davran

19:00, 19th August, 2020

Другие применения, которые я нашел для него, Кроме + и *, были с и И ИЛИ, но теперь у нас есть any и all , чтобы заменить эти случаи.

foldl и foldr действительно часто встречаются в схеме...

Вот некоторые милые обычаи:

Сгладить список

Цель: превратить [[1, 2, 3], [4, 5], [6, 7, 8]] в [1, 2, 3, 4, 5, 6, 7, 8] .

reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])

Список цифр в число

Цель: превратить [1, 2, 3, 4, 5, 6, 7, 8] в 12345678 .

Уродливый, медленный путь:

int("".join(map(str, [1,2,3,4,5,6,7,8])))

Довольно reduce путь:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)


  Сведения об ответе

SSESION

14:30, 5th August, 2020

reduce() можно использовать для поиска наименьшего общего кратного для 3 и более чисел :

#!/usr/bin/env python
from fractions import gcd
from functools import reduce

def lcm(*args):
    return reduce(lambda a,b: a * b // gcd(a, b), args)

Пример:

>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560


  Сведения об ответе

SSESION

23:48, 27th August, 2020

reduce() может использоваться для разрешения пунктирных имен (где eval() слишком опасно использовать):

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>


  Сведения об ответе

lourence

22:57, 15th August, 2020

Найти точку пересечения заданных списков:

input_list = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

result = reduce(set.intersection, map(set, input_list))

возвращается:

result = set([3, 4, 5])

via: Python-пересечение двух списков


  Сведения об ответе

darknet

16:44, 4th August, 2020

Я думаю, что это глупая команда. Следовательно:

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')


  Сведения об ответе

baggs

08:59, 27th August, 2020

Использование reduce , которое я нашел в своем коде, включало ситуацию, когда у меня была некоторая структура класса для логического выражения, и мне нужно было преобразовать список этих объектов выражения в конъюнкцию выражений. У меня уже была функция make_and для создания конъюнкции, заданной двумя выражениями, поэтому я написал reduce(make_and,l) . (Я знал, что список не был пустым; в противном случае это было бы что-то вроде reduce(make_and,l,make_true) .)

Именно по этой причине (некоторые) функциональные программисты любят reduce (или fold -функции, как обычно называются такие функции). Часто уже существует множество двоичных функций, таких как + , * , min , max , конкатенация и, в моем случае, make_and и make_or . Наличие reduce делает тривиальным перенос этих операций в списки (или деревья, или что там у вас есть, для функций сгиба в целом).

Конечно, если некоторые экземпляры (например, sum ) часто используются, то вы не хотите продолжать писать reduce . Однако вместо того, чтобы определять sum с помощью некоторого цикла for, вы можете так же легко определить его с помощью reduce .

Читабельность, как упоминали другие, действительно является проблемой. Однако вы можете возразить, что единственная причина, по которой люди находят reduce меньше "clear", заключается в том, что это не та функция, которую многие люди знают и/или используют.


  Сведения об ответе

lesha

12:35, 19th August, 2020

Вы можете заменить value = json_obj['a']['b']['c']['d']['e'] на:

value = reduce(dict.__getitem__, 'abcde', json_obj)

Если у вас уже есть путь a/b/c/.. в виде списка. Например, измените значения в dict вложенных диктов с помощью элементов в списке .


  Сведения об ответе

pumpa

01:13, 20th August, 2020

Состав функций: Если у вас уже есть список функций, которые вы хотите применить последовательно, например:

color = lambda x: x.replace('brown', 'blue')
speed = lambda x: x.replace('quick', 'slow')
work = lambda x: x.replace('lazy', 'industrious')
fs = [str.lower, color, speed, work, str.title]

Затем вы можете применить их все последовательно с:

>>> call = lambda s, func: func(s)
>>> s = "The Quick Brown Fox Jumps Over the Lazy Dog"
>>> reduce(call, fs, s)
'The Slow Blue Fox Jumps Over The Industrious Dog'

В этом случае цепочка методов может быть более читабельной. Но иногда это невозможно, и такая композиция может быть более читаемой и поддерживаемой, чем синтаксис типа f1(f2(f3(f4(x)))) .


  Сведения об ответе

fo_I_K

17:31, 4th August, 2020

@Blair Конрад: вы также можете реализовать свой glob/reduce с помощью sum, например:

files = sum([glob.glob(f) for f in args], [])

Это менее многословно, чем любой из ваших двух примеров, является совершенно Питонским и по-прежнему представляет собой только одну строку кода.

Поэтому, чтобы ответить на первоначальный вопрос, я лично стараюсь избегать использования reduce, потому что это никогда не бывает действительно необходимо, и я нахожу его менее ясным, чем другие подходы. Однако некоторые люди привыкают к сокращению и предпочитают его перечислению понятий (особенно Haskell программистов). Но если вы еще не думаете о проблеме с точки зрения сокращения, вам, вероятно, не нужно беспокоиться об ее использовании.


  Сведения об ответе

SSESION

04:06, 14th August, 2020

reduce может использоваться для поддержки цепных поисков атрибутов:

reduce(getattr, ('request', 'user', 'email'), self)

Конечно, это равносильно тому, чтобы

self.request.user.email

но это полезно, когда ваш код должен принимать произвольный список атрибутов.

(Цепные атрибуты произвольной длины часто используются при работе с моделями Django.)


  Сведения об ответе

прога

02:25, 25th August, 2020

Я пишу функцию compose для языка, поэтому я строю составленную функцию, используя reduce вместе с моим оператором apply.

В двух словах, compose берет список функций, чтобы составить в единую функцию. Если у меня есть сложная операция, которая применяется поэтапно, я хочу собрать все это вместе вот так:

complexop = compose(stage4, stage3, stage2, stage1)

Таким образом, я могу применить его к выражению типа so:

complexop(expression)

И я хочу, чтобы это было эквивалентно:

stage4(stage3(stage2(stage1(expression))))

Теперь, чтобы построить мои внутренние объекты, я хочу, чтобы он сказал::

Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x'))))))

(Класс Lambda создает определяемую пользователем функцию,а Apply создает приложение-функцию.)

Так вот, редуцировать, к сожалению, складки не в ту сторону, поэтому я в итоге использовал, грубо говоря:

reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')]))

Чтобы выяснить, что производит reduce, попробуйте их в REPL:

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))


  Сведения об ответе

COOL

11:50, 27th August, 2020

После греппинга моего кода кажется, что единственное, для чего я использовал reduce, - это вычисление факториала:

reduce(operator.mul, xrange(1, x+1) or (1,))


  Сведения об ответе

pumpa

02:49, 25th August, 2020

Не уверен, что это то, что вам нужно, но вы можете искать исходный код в Google .

Перейдите по ссылке для поиска по 'function:reduce() lang:python' в Google Code search

На первый взгляд следующие проекты используют reduce()

  • MoinMoin
  • Синец
  • Числовой
  • ScientificPython

и т.д. и т.д. но тогда это вряд ли удивительно, так как это огромные проекты.

Функциональность reduce может быть реализована с помощью рекурсии функций, которая, как мне кажется, была более явной, чем предполагал Гвидо.

Обновление:

Поскольку поиск кода Google был прекращен на 15-Jan-2012, помимо возврата к обычным поискам Google, есть нечто под названием Коллекция фрагментов кода , которая выглядит многообещающе. Ряд других ресурсов упоминаются в ответах на этот (закрытый) вопрос замена Google Code Search? .

Обновление 2 (29-May-2017):

Хорошим источником для примеров Python (в открытом коде) является Nullege search engine .


  Сведения об ответе

JUST___

14:11, 10th August, 2020

Reduce не ограничивается операциями scalar; он также может использоваться для сортировки вещей в корзины. (Именно для этого я чаще всего использую reduce).

Представьте себе случай, когда у вас есть список объектов, и вы хотите переорганизовать его иерархически, основываясь на свойствах, хранящихся в объекте. В следующем примере я создаю список объектов метаданных, связанных со статьями в газете с кодировкой XML с помощью функции articles . articles генерирует список из XML элементов, а затем сопоставляет их один за другим, создавая объекты, которые содержат некоторую интересную информацию о них. На переднем конце я собираюсь позволить пользователю просматривать статьи по section/subsection/headline. Поэтому я использую reduce , чтобы взять список статей и вернуть один словарь, который отражает иерархию section/subsection/article.

from lxml import etree
from Reader import Reader

class IssueReader(Reader):
    def articles(self):
        arts = self.q('//div3')  # inherited ... runs an xpath query against the issue
        subsection = etree.XPath('./ancestor::div2/@type')
        section = etree.XPath('./ancestor::div1/@type')
        header_text = etree.XPath('./head//text()')
        return map(lambda art: {
            'text_id': self.id,
            'path': self.getpath(art)[0],
            'subsection': (subsection(art)[0] or '[none]'),
            'section': (section(art)[0] or '[none]'),
            'headline': (''.join(header_text(art)) or '[none]')
        }, arts)

    def by_section(self):
        arts = self.articles()

        def extract(acc, art):  # acc for accumulator
            section = acc.get(art['section'], False)
            if section:
                subsection = acc.get(art['subsection'], False)
                if subsection:
                    subsection.append(art)
                else:
                    section[art['subsection']] = [art]
            else:
                acc[art['section']] = {art['subsection']: [art]}
            return acc

        return reduce(extract, arts, {})

Я даю здесь обе функции, потому что думаю, что это показывает, как map и reduce могут хорошо дополнять друг друга при работе с объектами. То же самое можно было бы сделать и с петлей for, ... но проведение серьезного времени с функциональным языком, как правило, заставляет меня думать в терминах map и reduce.

Кстати , если у кого-то есть лучший способ установить свойства, как я делаю в extract, где родители свойства, которое вы хотите установить, возможно, еще не существуют, пожалуйста, дайте мне знать.


  Сведения об ответе

davran

12:42, 25th August, 2020

reduce полезно, когда вам нужно найти объединение или пересечение последовательности set-подобных объектов.

>>> reduce(operator.or_, ({1}, {1, 2}, {1, 3}))  # union
{1, 2, 3}
>>> reduce(operator.and_, ({1}, {1, 2}, {1, 3}))  # intersection
{1}

(Помимо фактических set s, примером таких объектов являются Q-объекты Django .)

С другой стороны, если вы имеете дело с bool s, Вы должны использовать any и all :

>>> any((True, False, True))
True


  Сведения об ответе

darknet

23:27, 28th August, 2020

reduce можно использовать для получения списка с максимальным N-м элементом

reduce(lambda x,y: x if x[2] > y[2] else y,[[1,2,3,4],[5,2,5,7],[1,6,0,2]])

вернул бы [5, 2, 5, 7] так как это список с максимальным 3-м элементом +


  Сведения об ответе

COOL

14:05, 11th August, 2020

import os

files = [
    # full filenames
    "var/log/apache/errors.log",
    "home/kane/images/avatars/crusader.png",
    "home/jane/documents/diary.txt",
    "home/kane/images/selfie.jpg",
    "var/log/abc.txt",
    "home/kane/.vimrc",
    "home/kane/images/avatars/paladin.png",
]

# unfolding of plain filiname list to file-tree
fs_tree = ({}, # dict of folders
           []) # list of files
for full_name in files:
    path, fn = os.path.split(full_name)
    reduce(
        # this fucction walks deep into path
        # and creates placeholders for subfolders
        lambda d, k: d[0].setdefault(k,         # walk deep
                                     ({}, [])), # or create subfolder storage
        path.split(os.path.sep),
        fs_tree
    )[1].append(fn)

print fs_tree
#({'home': (
#    {'jane': (
#        {'documents': (
#           {},
#           ['diary.txt']
#        )},
#        []
#    ),
#    'kane': (
#       {'images': (
#          {'avatars': (
#             {},
#             ['crusader.png',
#             'paladin.png']
#          )},
#          ['selfie.jpg']
#       )},
#       ['.vimrc']
#    )},
#    []
#  ),
#  'var': (
#     {'log': (
#         {'apache': (
#            {},
#            ['errors.log']
#         )},
#         ['abc.txt']
#     )},
#     [])
#},
#[])


  Сведения об ответе

FAriza

17:40, 3rd August, 2020

def dump(fname,iterable):
  with open(fname,'w') as f:
    reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable)


  Сведения об ответе

SEEYOU

19:20, 24th August, 2020

Я использовал reduce для объединения списка векторов поиска PostgreSQL с оператором || в sqlalchemy-searchable:

vectors = (self.column_vector(getattr(self.table.c, column_name))
           for column_name in self.indexed_columns)
concatenated = reduce(lambda x, y: x.op('||')(y), vectors)
compiled = concatenated.compile(self.conn)


  Сведения об ответе

Chhiki

07:00, 28th August, 2020

У меня есть старая реализация Python pipegrep, которая использует reduce и модуль glob для создания списка файлов для обработки:

files = []
files.extend(reduce(lambda x, y: x + y, map(glob.glob, args)))

Я нашел его удобным в то время, но это действительно не нужно, так как что-то подобное так же хорошо, и, вероятно, более читабельно

files = []
for f in args:
    files.extend(glob.glob(f))


  Сведения об ответе

DINO

12:52, 21st August, 2020

Пусть говорят, что есть некоторые ежегодные статистические данные, хранящиеся в списке счетчиков. Мы хотим найти минимальные / максимальные значения в каждом месяце в разные годы. Например, для января это будет be 10. А для февраля это будет be 15. Нам нужно сохранить результаты в новом счетчике.

from collections import Counter

stat2011 = Counter({"January": 12, "February": 20, "March": 50, "April": 70, "May": 15,
           "June": 35, "July": 30, "August": 15, "September": 20, "October": 60,
           "November": 13, "December": 50})

stat2012 = Counter({"January": 36, "February": 15, "March": 50, "April": 10, "May": 90,
           "June": 25, "July": 35, "August": 15, "September": 20, "October": 30,
           "November": 10, "December": 25})

stat2013 = Counter({"January": 10, "February": 60, "March": 90, "April": 10, "May": 80,
           "June": 50, "July": 30, "August": 15, "September": 20, "October": 75,
           "November": 60, "December": 15})

stat_list = [stat2011, stat2012, stat2013]

print reduce(lambda x, y: x & y, stat_list)     # MIN
print reduce(lambda x, y: x | y, stat_list)     # MAX


  Сведения об ответе

dumai

12:36, 16th August, 2020

У меня есть объекты, представляющие собой своего рода перекрывающиеся интервалы (геномные экзоны), и я переопределил их пересечение с помощью __and__ :

class Exon:
    def __init__(self):
        ...
    def __and__(self,other):
        ...
        length = self.length + other.length  # (e.g.)
        return self.__class__(...length,...)

Затем, когда у меня есть их коллекция (например, в одном и том же гене), я использую

intersection = reduce(lambda x,y: x&y, exons)


  Сведения об ответе

screen

03:44, 8th August, 2020

Я только что нашел полезное использование reduce: разделение строки без удаления разделителя . Код полностью взят из программно говорящего блога. Вот этот код:

reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem == "\n" else acc + [elem], re.split("(\n)", "a\nb\nc\n"), [])

Вот вам и результат:

['a\n', 'b\n', 'c\n', '']

Обратите внимание, что он обрабатывает крайние случаи, которые популярный ответ в SO не делает. для более подробного объяснения я перенаправляю вас на оригинальный пост в блоге.


  Сведения об ответе

nYU

00:55, 29th August, 2020

Используя reduce(), чтобы узнать, является ли список дат последовательным:

from datetime import date, timedelta


def checked(d1, d2):
    """
    We assume the date list is sorted.
    If d2 & d1 are different by 1, everything up to d2 is consecutive, so d2
    can advance to the next reduction.
    If d2 & d1 are not different by 1, returning d1 - 1 for the next reduction
    will guarantee the result produced by reduce() to be something other than
    the last date in the sorted date list.

    Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
    Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

    """
    #if (d2 - d1).days == 1 or (d2 - d1).days == 0:  # for Definition 1
    if (d2 - d1).days == 1:                          # for Definition 2
        return d2
    else:
        return d1 + timedelta(days=-1)

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

if datelist[-1] == reduce(checked, datelist):
    print "dates are consecutive"
else:
    print "dates are not consecutive"


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться