Nyttige kode som bruker redusere ()?

stemmer
114

Har noen her har noe nyttig kode som bruker redusere () -funksjonen i python? Er det noen kode enn vanlig + og * som vi ser i eksemplene?

Henvis Fate of redusere () i Python 3000 av GVR

Publisert på 19/08/2008 klokken 11:16
kilden bruker
På andre språk...                            


24 svar

stemmer
63

De andre bruker jeg har funnet for det foruten + og * var med og og eller, men nå har vi anyog allerstatte disse tilfellene.

foldlog foldrkommer opp i skjema mye ...

Her er noen søte bruksområder:

Flat en liste

Mål: slår [[1, 2, 3], [4, 5], [6, 7, 8]]inn [1, 2, 3, 4, 5, 6, 7, 8].

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

Liste over sifre til et tall

Mål: slår [1, 2, 3, 4, 5, 6, 7, 8]inn 12345678.

Stygg, treg måte:

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

Pretty reducemåte:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
Svarte 11/11/2008 kl. 07:29
kilden bruker

stemmer
47

reduce()kan brukes til å finne minste felles multiplum for 3 eller flere tall :

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

Eksempel:

>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
Svarte 11/11/2008 kl. 21:33
kilden bruker

stemmer
35

reduce()kan brukes til å løse stiplede navn (der eval()er for utrygt å bruke):

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>
Svarte 12/11/2008 kl. 01:02
kilden bruker

stemmer
21

Finn skjæringspunktet mellom N gitte lister:

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

avkastning:

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

via: Python - skjæringspunktet mellom to lister

Svarte 17/07/2010 kl. 17:05
kilden bruker

stemmer
11

Jeg tror redusere er en dum kommando. Derfor:

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')
Svarte 29/08/2012 kl. 05:34
kilden bruker

stemmer
11

Bruken av reducedet jeg fant i min kode involvert situasjonen der jeg hadde noen klassestrukturen for logikk uttrykk og jeg trengte å konvertere en liste over disse uttrykk gjenstander til en forbindelse av uttrykkene. Jeg hadde allerede en funksjon make_andfor å opprette en forbindelse gitt to uttrykk, så jeg skrev reduce(make_and,l). (Jeg visste listen var ikke tom, ellers ville det ha vært noe sånt reduce(make_and,l,make_true).)

Dette er nettopp grunnen til at (noen) funksjonelle programmerere som reduce(eller fold funksjoner, som slike funksjoner er vanligvis kalles). Det er ofte allerede mange binære funksjoner som +, *, min, max, sammensetning og, i mitt tilfelle, make_andog make_or. Å ha en reducegjør det trivielt å løfte disse operasjonene til lister (eller trær eller hva du fikk, for fold funksjoner generelt).

Selvfølgelig, hvis visse instantiations (for eksempel sum) blir ofte brukt, så du ikke ønsker å fortsette å skrive reduce. Men i stedet for å definere den summed noen for-loop, du kan like gjerne definere det med reduce.

Lesbarhet, som nevnt av andre, er faktisk et problem. Du kan argumentere imidlertid at eneste grunnen til at folk finner reducemindre "klar" er fordi det ikke er en funksjon som mange kjenner og / eller bruk.

Svarte 03/09/2008 kl. 13:27
kilden bruker

stemmer
7

Du kan erstatte value = json_obj['a']['b']['c']['d']['e']med:

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

Hvis du allerede har banen a/b/c/..som en liste. For eksempel, Endre verdier i dict av nestet dicts bruker elementer i en liste .

Svarte 19/08/2012 kl. 11:15
kilden bruker

stemmer
7

@Blair Conrad: Du kan også implementere glob / redusere ved hjelp av summen, som så:

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

Dette er mindre detaljert enn noen av dine to eksempler, er helt Pytonske, og er fortsatt bare en linje med kode.

Så for å svare på det opprinnelige spørsmålet, jeg personlig prøver å unngå å bruke redusere fordi det er aldri virkelig nødvendig, og jeg synes det å være mindre klart enn andre tilnærminger. Men noen folk blir vant til å redusere og komme til å foretrekke det å liste oppfattelser (spesielt Haskell programmerere). Men hvis du ikke allerede tenker på et problem når det gjelder å redusere, har du sannsynligvis ikke trenger å bekymre deg for å bruke det.

Svarte 19/08/2008 kl. 13:57
kilden bruker

stemmer
6

Funksjon sammensetning : Hvis du allerede har en liste over funksjoner som du ønsker å søke etter hverandre, for eksempel:

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]

Deretter kan du bruke dem alle etter hverandre med:

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

I dette tilfellet kan fremgangsmåten kjeding være lettere å lese. Men noen ganger er det ikke mulig, og denne typen sammensetning kan være mer lesbart og vedlikeholdsvennlig enn en f1(f2(f3(f4(x))))slags syntaks.

Svarte 15/01/2014 kl. 17:55
kilden bruker

stemmer
5

reduce kan brukes til å støtte lenket attributt oppslag:

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

Selvfølgelig er dette tilsvarer

self.request.user.email

men det er nyttig når koden din må akseptere en vilkårlig liste med attributter.

(Lenket attributter av vilkårlig lengde som er vanlig når det arbeider med Django modeller.)

Svarte 20/06/2014 kl. 07:07
kilden bruker

stemmer
3

reduceer nyttig når du trenger å finne unionen eller kryss av en sekvens av set-lignende stedene.

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

(Bortsett fra selve sets, et eksempel på disse er Djangos Q objekter .)

På den annen side, hvis du arbeider med bools, bør du bruke anyog all:

>>> any((True, False, True))
True
Svarte 20/06/2014 kl. 07:37
kilden bruker

stemmer
3

Redusere er ikke begrenset til skalare operasjoner; Det kan også brukes til å sortere ting i bøtter. (Dette er hva jeg bruker redusere for oftest).

Tenk deg et tilfelle der du har en liste over objekter, og du ønsker å re-organisere det hierarkisk basert på egenskaper som er lagret flatt i objektet. I det følgende eksempel, fremstille jeg en liste over metadataobjekter forbundet med artiklene i en XML-kodet avis med den articlesfunksjonen. articlesgenererer en liste av XML-elementer, og deretter tilordner gjennom dem én etter én, produsere gjenstander som holder litt interessant informasjon om dem. På den fronten, jeg kommer til å ønske å la brukeren bla gjennom artikler av seksjon / ledd / overskrift. Så jeg bruker reduceå ta en liste over artikler og returnere en eneste ordbok som gjenspeiler den delen / ledd / artikkel hierarki.

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

Jeg gir begge funksjoner her fordi jeg tror det viser hvordan kartlegge og redusere kan utfylle hverandre pent når du arbeider med objekter. Det samme kunne vært oppnådd med en for loop, ... men tilbringe litt alvorlig tid med et funksjonelt språk har en tendens til å gjøre meg til å tenke i form av kart og redusere.

Forresten, hvis noen har en bedre måte å sette egenskaper som jeg gjør i extract, hvor foreldrene av eiendommen du ønsker å sette kanskje ikke eksisterer ennå, kan du gi meg beskjed.

Svarte 07/09/2012 kl. 02:23
kilden bruker

stemmer
3

Jeg skriver en komponere funksjon for et språk, så jeg konstruere sammensatt funksjon med å redusere sammen med min gjelder operatør.

I et nøtteskall, komponere tar en liste over funksjoner for å komponere til en enkelt funksjon. Hvis jeg har en kompleks operasjon som er brukt i etapper, jeg ønsker å sette det hele sammen slik:

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

På denne måten kan jeg da bruke den til et uttrykk som så:

complexop(expression)

Og jeg vil den skal være tilsvarende:

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

Nå, for å bygge mine interne objekter, jeg ønsker å si:

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

(Lambda klasse bygger en brukerdefinert funksjon, og Påfør bygger en funksjon søknad).

Nå, redusere, dessverre, folder på feil måte, så jeg endte opp med, omtrent:

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

For å finne ut hva redusere produserer, prøv disse i ERSTATTER:

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))
Svarte 23/04/2010 kl. 20:34
kilden bruker

stemmer
3

Etter grepping koden min, synes det er det eneste jeg har brukt å redusere for beregner fakultet:

reduce(operator.mul, xrange(1, x+1) or (1,))
Svarte 21/08/2008 kl. 21:40
kilden bruker

stemmer
3

Ikke sikker på om dette er hva du er ute etter, men du kan søke kildekoden på Google .

Følg linken for et søk på 'funksjon: å redusere () lang: python' på søk Google Code

Ved første øyekast følgende prosjekter bruker reduce()

  • Interessante sider
  • Zope
  • numerisk
  • ScientificPython

etc. etc. men da disse er neppe overraskende siden de er store prosjekter.

Funksjonaliteten redusere kan gjøres ved hjelp av funksjonen rekursjon som jeg tror Guido trodde var mer eksplisitt.

Oppdater:

Siden Google Code Search ble avviklet på 15-Jan-2012, i tillegg til å gå tilbake til vanlig Google-søk, er det noe som heter kodesnutter Collection som ser lovende ut. En rekke andre ressurser er nevnt i svarene dette (stengt) spørsmålet Erstatning for Google Code Search? .

Oppdater 2 (29-mai-2017):

En god kilde for Python eksempler (i open-source-kode) er den Nullege søkemotor .

Svarte 19/08/2008 kl. 12:16
kilden bruker

stemmer
2

Jeg pleide reduce å sette sammen en liste over PostgreSQL søke vektorer med ||operatøren i sqlalchemy-søkbar:

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)
Svarte 06/01/2016 kl. 04:10
kilden bruker

stemmer
2
def dump(fname,iterable):
  with open(fname,'w') as f:
    reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable)
Svarte 16/09/2015 kl. 14:43
kilden bruker

stemmer
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']
#     )},
#     [])
#},
#[])
Svarte 20/05/2014 kl. 16:08
kilden bruker

stemmer
1

Jeg har funnet nyttig bruk av reduce: splitting strengen uten å fjerne skilletegn . Koden er helt fra auto Snakker blogg. Her er koden:

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

Her er resultatet:

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

Merk at den håndterer ende saker som populære svaret i så gjør det ikke. For mer inngående forklaring, jeg omdirigere deg til opprinnelig blogginnlegg.

Svarte 24/11/2015 kl. 13:31
kilden bruker

stemmer
1

Jeg har objekter som representerer en slags overlappende intervaller (genomisk exoner), og redefinert deres skjæringspunkt ved hjelp av __and__:

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

Da jeg har en samling av dem (for eksempel i det samme gen), bruker jeg

intersection = reduce(lambda x,y: x&y, exons)
Svarte 05/06/2014 kl. 13:40
kilden bruker

stemmer
1

La oss si at det er noen årlige statistiske data som er lagret en liste over tellere. Vi ønsker å finne MIN / MAX verdier i hver måned på tvers av de ulike årene. For eksempel, for januar vil det være 10. Og for februar vil det være 15. Vi trenger å lagre resultatene i en ny Counter.

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
Svarte 22/02/2014 kl. 15:18
kilden bruker

stemmer
1

redusere kan brukes for å få listen med maksimal n-te element

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

vil returnere [5, 2, 5, 7] som det er en liste med max tredje element +

Svarte 21/03/2013 kl. 07:06
kilden bruker

stemmer
1

Jeg har en gammel Python implementering av pipegrep som bruker redusere og glob modulen for å bygge en liste over filer til prosessen:

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

Jeg fant det nyttig på den tiden, men det er egentlig ikke nødvendig, så noe lignende er like bra, og sannsynligvis mer lesbar

files = []
for f in args:
    files.extend(glob.glob(f))
Svarte 19/08/2008 kl. 12:43
kilden bruker

stemmer
0

Bruke redusere () for å finne ut om en liste over datoer er på rad:

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"
Svarte 22/02/2014 kl. 15:16
kilden bruker

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