código útil que usa reduzir ()?

votos
113

Alguém aqui tem qualquer código útil que usa reduzir a função () em python? Existe algum código diferente do que o habitual + e * que vemos nos exemplos?

Consulte Fate of reduzir () em Python 3000 por GvR

Publicado 19/08/2008 em 12:16
fonte usuário
Em outras línguas...                            


24 respostas

votos
63

Os outros usos que eu encontrei para ele além de + e * foram com AND e OR, mas agora nós temos anye allpara substituir esses casos.

foldle foldrvêm-se no Esquema muito ...

Eis alguns usos bonito:

Achatar uma lista

Objetivo: transformar [[1, 2, 3], [4, 5], [6, 7, 8]]em [1, 2, 3, 4, 5, 6, 7, 8].

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

Lista de dígitos para um número

Objetivo: transformar [1, 2, 3, 4, 5, 6, 7, 8]em 12345678.

Feio, forma lenta:

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

Consideravelmente reducemaneira:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
Respondeu 11/11/2008 em 08:29
fonte usuário

votos
47

reduce()pode ser usado para encontrar Mínimo múltiplo comum para 3 ou mais números :

#!/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)

Exemplo:

>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
Respondeu 11/11/2008 em 22:33
fonte usuário

votos
35

reduce()poderia ser usado para resolver nomes pontilhadas (onde eval()é muito inseguro para usar):

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>
Respondeu 12/11/2008 em 02:02
fonte usuário

votos
20

Encontre o cruzamento de listas N dadas:

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

retorna:

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

via: Python - interseção de duas listas

Respondeu 17/07/2010 em 18:05
fonte usuário

votos
11

Acho que reduzir é um comando bobo. Conseqüentemente:

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')
Respondeu 29/08/2012 em 06:34
fonte usuário

votos
11

O uso do reduceque eu encontrei no meu código envolveu a situação onde eu tinha alguma estrutura de classe para a expressão lógica e eu precisava para converter uma lista dessas expressão objetos a uma conjunção das expressões. Eu já tinha uma função make_andpara criar um conjunto dado duas expressões, então eu escrevi reduce(make_and,l). (Eu sabia que a lista não estava vazia; caso contrário, teria sido algo como reduce(make_and,l,make_true).)

Esta é exactamente a razão que (alguns) programadores funcionais, como reduce(ou dobra funções, como tais funções são tipicamente chamado). Muitas vezes há já muitas funções binárias como +, *, min, max, concatenação e, no meu caso, make_ande make_or. Ter um reducetorna trivial para levantar estas operações para listas (ou árvores ou qualquer outra coisa que você tem, para as funções de dobra em geral).

Claro que, se certas instâncias (tais como sum) são usados muitas vezes, então você não quer manter a escrita reduce. No entanto, em vez de definir o sumcom alguma for-loop, você pode simplesmente defini-lo como facilmente com reduce.

Legibilidade, como mencionado por outros, é realmente um problema. Você pode argumentar, no entanto, que só a razão por que as pessoas encontram reducemenos "claro" é porque ele não é uma função que muitas pessoas sabem e / ou utilização.

Respondeu 03/09/2008 em 14:27
fonte usuário

votos
7

Você poderia substituir value = json_obj['a']['b']['c']['d']['e']com:

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

Se você já tem o caminho a/b/c/..como uma lista. Por exemplo, alterar os valores em dict de dicts aninhados usando itens em uma lista .

Respondeu 19/08/2012 em 12:15
fonte usuário

votos
7

@Blair Conrad: Você também pode implementar sua glob / reduzir utilizando soma, assim:

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

Isso é menos detalhado do que qualquer um de seus dois exemplos, é perfeitamente Pythonic, e ainda é apenas uma linha de código.

Então, para responder à pergunta original, eu, pessoalmente, tentar evitar o uso reduzir porque nunca é realmente necessário e eu acho que ele seja menos claro do que outras abordagens. No entanto, algumas pessoas se acostumar a reduzir e venha a preferi-la à lista compreensões (especialmente programadores de Haskell). Mas se você não estiver pensando em um problema em termos de reduzir, você provavelmente não precisa se preocupar com a usá-lo.

Respondeu 19/08/2008 em 14:57
fonte usuário

votos
4

reduce pode ser usado para apoiar pesquisas de atributos encadeadas:

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

Claro, isso é equivalente a

self.request.user.email

mas é útil quando o seu código precisa aceitar uma lista arbitrária de atributos.

(Atributos encadeados de comprimento arbitrário são comuns ao lidar com modelos Django.)

Respondeu 20/06/2014 em 08:07
fonte usuário

votos
4

Composição de funções : Se você já tem uma lista de funções que você gostaria de aplicar em sucessão, tais como:

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]

Depois, você pode aplicá-las todas consecutivamente com:

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

Neste caso, o método de encadeamento pode ser mais legível. Mas às vezes não é possível, e esse tipo de composição pode ser mais legível e de fácil manutenção do que um f1(f2(f3(f4(x))))tipo de sintaxe.

Respondeu 15/01/2014 em 18:55
fonte usuário

votos
3

reduceé útil quando você precisa encontrar a união ou intersecção de uma sequência de set-como objetos.

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

(Além de reais sets, um exemplo destes são objectos Q do Django .)

Por outro lado, se você está lidando com bools, você deve usar anye all:

>>> any((True, False, True))
True
Respondeu 20/06/2014 em 08:37
fonte usuário

votos
3

Reduzir não está limitada a operações escalares; ele também pode ser usado para classificar as coisas em baldes. (Isto é o que eu uso reduzir para na maioria das vezes).

Imagine um caso em que você tem uma lista de objetos, e você quer re-organizar hierarquicamente com base em propriedades armazenadas categoricamente no objeto. No exemplo a seguir, eu produzir uma lista de objetos de metadados relacionados com artigos em um jornal codificado em XML com a articlesfunção. articlesgera uma lista de elementos XML, e em seguida, mapeia através deles, um por um, produzindo objetos que mantêm alguma informação interessante sobre eles. No front-end, eu vou querer deixar o usuário ver alguns dos artigos de seção / subseção / manchete. Então, eu uso reducepara tomar a lista de artigos e retornar um único dicionário que reflete o / subseção / artigo hierarquia seção.

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, {})

Eu dou as duas funções aqui porque eu acho que mostra como mapear e reduzir podem complementar-se muito bem ao lidar com objetos. A mesma coisa poderia ter sido realizado com um loop for, ... mas passar algum tempo sério com uma linguagem funcional tende a me fazer pensar em termos de mapa e reduzir.

By the way, se alguém tem uma maneira melhor para definir propriedades como eu estou fazendo em extract, onde os pais da propriedade que você deseja definir pode não existir ainda, por favor me avise.

Respondeu 07/09/2012 em 03:23
fonte usuário

votos
3

Eu estou escrevendo uma função de compor para uma linguagem, então eu construir a função composta usando reduzir juntamente com a minha operador aplica.

Em poucas palavras, componha toma uma lista de funções para compor em uma única função. Se eu tiver uma operação complexa que é aplicada em etapas, quero colocá-lo todos juntos assim:

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

Dessa forma, posso depois aplicá-lo a uma expressão assim:

complexop(expression)

E eu quero que seja equivalente a:

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

Agora, para construir meus objetos internos, eu quero dizer:

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

(A classe Lambda constrói uma função definida pelo utilizador, e Aplicar constrói um pedido de função).

Agora, reduzir, infelizmente, se dobra para o lado errado, então acabei usando, aproximadamente:

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

Para descobrir o que reduz produz, tente estes no REPL:

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))
Respondeu 23/04/2010 em 21:34
fonte usuário

votos
3

Depois grepping meu código, parece que a única coisa que eu usei reduzir para se calcular o fatorial:

reduce(operator.mul, xrange(1, x+1) or (1,))
Respondeu 21/08/2008 em 22:40
fonte usuário

votos
3

Não tenho certeza se é isso que você está depois, mas você pode procurar código fonte no Google .

Siga o link para uma pesquisa sobre 'função: reduzir () lang: python' na pesquisa do Google Code

À primeira vista, as seguintes projectos utilizam reduce()

  • MoinMoin
  • Zope
  • Numérico
  • ScientificPython

etc. etc., mas, em seguida, estes são de surpreender, uma vez que são projetos enormes.

A funcionalidade de reduzir pode ser feito usando a função de recursão que eu acho que Guido pensava ser mais explícito.

Atualizar:

Desde Code Search do Google foi descontinuado em 15-Jan-2012, além de reverter para pesquisas regulares do Google, há algo chamado de trechos de código coleção que parece promissor. Uma série de outros recursos são mencionados nas respostas deste (fechado) questão de substituição para o Google Code Search? .

Atualização 2 (29-May-2017):

Uma boa fonte para exemplos de Python (em código-fonte aberto) é o motor de pesquisa Nullege .

Respondeu 19/08/2008 em 13:16
fonte usuário

votos
2

I utilizado reduce para concatenar uma lista de vetores de busca PostgreSQL com o ||operador na sqlalchemy pesquisável:

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)
Respondeu 06/01/2016 em 04:10
fonte usuário

votos
2
def dump(fname,iterable):
  with open(fname,'w') as f:
    reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable)
Respondeu 16/09/2015 em 14:43
fonte usuário

votos
2
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']
#     )},
#     [])
#},
#[])
Respondeu 20/05/2014 em 17:08
fonte usuário

votos
1

Eu só descobri o uso útil de reduce: corda divisão sem remover o delimitador . O código é inteiramente de Programatically blogue Falando. Aqui está o código:

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

Aqui está o resultado:

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

Note-se que ele lida com casos de ponta que a resposta popular na SO não. Para obter mais explicações em profundidade, estou redirecionando você para post originais.

Respondeu 24/11/2015 em 13:31
fonte usuário

votos
1

Eu tenho objetos que representam algum tipo de sobreposição de intervalos (exons genómico), e redefiniu sua interseção usando __and__:

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

Em seguida, quando tem uma colecção deles (por exemplo, no mesmo gene), eu uso

intersection = reduce(lambda x,y: x&y, exons)
Respondeu 05/06/2014 em 14:40
fonte usuário

votos
1

Vamos dizer que há alguns dados estatísticos anuais armazenados uma lista de contadores. Queremos encontrar os valores MIN / MAX em cada mês através dos diferentes anos. Por exemplo, para janeiro seria 10. E para fevereiro seria 15. Precisamos armazenar os resultados em um novo contador.

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
Respondeu 22/02/2014 em 16:18
fonte usuário

votos
1

reduzir pode ser usado para obter a lista com o elemento máximo enésimo

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

voltaria [5, 2, 5, 7], uma vez que a lista com max 3 + elemento

Respondeu 21/03/2013 em 08:06
fonte usuário

votos
1

Eu tenho uma implementação de idade Python de pipegrep que usa reduzir e o módulo glob para construir uma lista de arquivos para processo:

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

Eu encontrei-o útil no momento, mas não é realmente necessário, como algo semelhante é tão bom, e provavelmente mais legível

files = []
for f in args:
    files.extend(glob.glob(f))
Respondeu 19/08/2008 em 13:43
fonte usuário

votos
0

Usando reduzir () para descobrir se uma lista de datas são consecutivas:

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"
Respondeu 22/02/2014 em 16:16
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more