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

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

Ссылайтесь на Судьбу снижения () в Python 3000 от GvR

19.08.2008 11:16:58
from functools import reduceпозволяет одному и тому же коду работать на Python 2 и 3.
jfs 11.01.2015 20:49:54
24 ОТВЕТА

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

Перейдите по ссылке для поиска по запросу «функция: уменьшить () lang: python» в поиске кода Google.

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

  • MoinMoin
  • Zope
  • числовой
  • ScientificPython

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

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

Обновить:

Поскольку поиск кода Google был прекращен 15 января 2012 года, помимо возврата к обычным поискам в Google, есть нечто, называемое Code Snippets Collection, которое выглядит многообещающим. В ответах на этот (закрытый) вопрос упоминается ряд других ресурсов. Замена для Google Code Search? ,

Обновление 2 (29 мая 2017 года):

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

3
30.05.2017 04:31:40
«Функциональность Reduce может быть выполнена с помощью функции рекурсии» ... Или forцикл.
Jason Orendorff 10.12.2009 23:13:59
Кроме того, при поиске Reduce () создаются проекты, которые определяют функции Reduce в своем коде. Вам нужно искать lang: python "
Seun Osewa 12.03.2010 18:08:50
@Seun Osewa: Даже поиск lang:python "reduce("найдет определения reduceзависимости от стиля кодирования исходного кода.
martineau 21.04.2011 18:32:13

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

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

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

files = []
for f in args:
    files.extend(glob.glob(f))
1
19.08.2008 12:43:36
Как насчет понимания списка? Это кажется идеальным приложением для этого: files = [glob.glob(f) for f in args]
steveha 11.03.2010 07:28:35
На самом деле, @steveha, ваш пример приведет к списку списков расширенных глобусов, а не к плоскому списку всех элементов, соответствующих глобусам, но вы можете использовать список понимания + сумма, как @ [Eli Courtwright] (# 16198 ) указывает на то.
Blair Conrad 12.03.2010 02:14:40
Хорошо, вы правы, извините за это. Мне все еще не очень нравится комбинация расширения / уменьшения / лямбды / карты! Я бы порекомендовал импортировать itertools, используя flatten()рецепт из docs.python.org/library/itertools.html , а затем написать: files = flatten(glob.glob(f) for f in args) (И на этот раз я проверил код перед публикацией, и я знаю, что он работает правильно.)
steveha 12.03.2010 20:04:37
files = chain.from_iterable(imap(iglob, args))where chain, imapfrom from itertoolsmodule и glob.iglobполезно, если шаблон from argsможет выдавать файлы из нескольких каталогов.
jfs 5.12.2012 06:11:00

@Blair Conrad: Вы могли бы также реализовать свой глобус / уменьшить, используя сумму, например так:

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

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

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

7
19.08.2008 13:57:22
И то sumи другое reduceведет к квадратичному поведению. Это может быть сделано в линейное время: files = chain.from_iterable(imap(iglob, args)). Хотя это, вероятно, не имеет значения в этом случае из-за времени, которое требуется glob () для доступа к диску.
jfs 5.12.2012 07:04:52

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

reduce(operator.mul, xrange(1, x+1) or (1,))
3
21.08.2008 21:40:46
Затем замените его на math.factorial docs.python.org/2/library/math.html#math.factorial
pihentagy 29.01.2013 14:32:44

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

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

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

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

11
3.09.2008 13:27:47
для защиты от пустого списка вы можете использовать поведение andоператора L and reduce(make_and, L)при коротком замыкании : если в этом случае уместно возвращать пустой список
jfs 5.12.2012 07:14:50

Другие применения, которые я нашел для этого, кроме + и *, были с и и или, но теперь мы имеем 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)
66
11.11.2008 07:29:36
Для выравнивания списка я предпочитаю list (itertools.chain (* nested_list))
Roberto Bonvallet 28.07.2009 19:59:09
сумма ([[1, 2, 3], [4, 5], [6, 7, 8]], [])
Gordon Wrigley 27.09.2010 12:47:37
Это также полезно для побитовых операций. Что, если вы хотите получить побитовое или набор чисел, например, если вам нужно преобразовать флаги из списка в битовую маску?
Antimony 15.10.2012 21:55:48
Делая некоторые тесты, «уродливый» способ быстрее для больших списков. timeit.repeat('int("".join(map(str, digit_list)))', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)занимает ~ 0,09 секунды, а timeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)занимает 0,36 секунды (примерно в 4 раза медленнее). В основном, умножение на 10 становится дорогим, когда список становится большим, а int to str и конкатенация остаются дешевыми.
dr jimbob 21.08.2013 17:18:16
Конечно, да для небольших списков (размер 10), тогда метод сокращения в 1,3 раза быстрее. Однако даже в этом случае обход сокращения и выполнение простого цикла происходит еще быстрее: timeit.repeat('convert_digit_list_to_int(digit_list)', setup = 'digit_list = [d%10 for d in xrange(1,10)]\ndef convert_digit_list_to_int(digits):\n i = 0\n for d in digits:\n i = 10*i + d\n return i', number=100000)0,06 с, timeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,10))', number=100000)0,12 с, а преобразование цифр в метод str - 0,16 с.
dr jimbob 21.08.2013 17:20:45

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
51
23.05.2017 12:34:30
Что находится lcmво второй строке?
beardc 24.05.2012 03:01:09
@BirdJaguarIV: перейдите по ссылке в ответе. lcm()возвращает наименьшее общее кратное двух чисел.
jfs 24.05.2012 11:51:00

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

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>
39
12.11.2008 01:02:23

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

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

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

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

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')]))

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

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))
3
23.04.2010 20:34:50
Я использовал compose = lambda *func: lambda arg: reduce(lambda x, f: f(x), reversed(funcs), arg)для генерации всех возможных комбинаций функций для тестирования производительности.
jfs 5.12.2012 06:00:47

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

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])

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

23
23.05.2017 11:47:07

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

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

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

9
30.05.2017 04:20:57

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

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')
12
29.08.2012 05:34:17
Мне также нравится ирония здесь
Roman 17.03.2016 11:57:07

Сокращение не ограничено скалярными операциями; это может также использоваться, чтобы сортировать вещи в ведра. (Это то, что я использую уменьшить чаще всего).

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

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 и сокращения могут хорошо дополнять друг друга при работе с объектами. То же самое можно было бы сделать с помощью цикла for, но затрачивание серьезного времени на функциональном языке, как правило, заставляло меня думать с точки зрения карты и сокращения.

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

3
25.09.2014 08:51:08

уменьшить можно использовать для получения списка с максимальным 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-м элементом +

3
21.03.2013 07:06:14
max (lst, key = lambda x: x [2])
aoeu256 16.10.2019 22:55:04

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

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))))вид синтаксиса.

9
15.01.2014 17:55:26
Преимущество состоит в том, что вы можете изменить список функций, применяемых в коде.
hakanc 15.09.2015 13:28:00

С помощью метода 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"
0
22.02.2014 15:16:42

Допустим, есть некоторые годовые статистические данные, хранящиеся в списке счетчиков. Мы хотим найти значения MIN / MAX в каждом месяце в разные годы. Например, для января это будет 10. А для февраля - 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
1
22.02.2014 15:18:17
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']
#     )},
#     [])
#},
#[])
2
26.09.2014 09:38:11
Не могли бы вы добавить небольшое объяснение тому, что здесь происходит? В противном случае полезность на самом деле совсем не очевидна.
Zoran Pavlovic 25.09.2014 08:36:01

У меня есть объекты, представляющие некоторый вид перекрывающихся интервалов (геномные экзоны), и я переопределил их пересечение, используя __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)
1
5.06.2014 13:40:37

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

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

Конечно, это эквивалентно

self.request.user.email

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

(Связанные атрибуты произвольной длины являются общими при работе с моделями Джанго.)

6
20.06.2014 07:07:29

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

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

(Помимо фактических sets, примером этого являются объекты Q Джанго .)

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

>>> any((True, False, True))
True
4
20.06.2014 07:37:15
def dump(fname,iterable):
  with open(fname,'w') as f:
    reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable)
2
16.09.2015 14:43:41

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

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. Для более подробного объяснения я перенаправляю вас к оригинальному сообщению в блоге.

1
24.11.2015 13:31:11

Я использовал 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)
2
6.01.2016 04:10:35