pyplot python functional-programming

python - pyplot - Código útil que usa reduce()?



title plt python (24)

@Blair Conrad: también podría implementar su glob / reducir usando suma, así:

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

Esto es menos detallado que cualquiera de tus dos ejemplos, es perfectamente pitónico y sigue siendo solo una línea de código.

Entonces, para responder a la pregunta original, trato de evitar el uso de reducir porque nunca es realmente necesario y me resulta menos claro que otros enfoques. Sin embargo, algunas personas se acostumbran a reducir y llegan a preferir enumerar las comprensiones (especialmente los programadores de Haskell). Pero si aún no está pensando en un problema en términos de reducción, probablemente no tenga que preocuparse por usarlo.

¿Alguien aquí tiene algún código útil que utiliza la función reduce () en Python? ¿Hay algún código diferente al habitual + y * que vemos en los ejemplos?

Consulte Destino de reducir () en Python 3000 por GvR


Acabo de encontrar el uso útil de reduce : dividir cadena sin eliminar el delimitador . El código es completamente del blog Programatically Speaking. Aquí está el código:

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

Este es el resultado:

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

Tenga en cuenta que maneja casos extremos que la respuesta popular en SO no lo hace. Para una explicación más detallada, te estoy redirigiendo a una publicación de blog original.


Creo que reducir es un comando tonto. Por lo tanto:

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


Después de guardar mi código, parece que lo único que he usado para reducir es calcular el factorial:

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


Digamos que hay algunos datos estadísticos anuales almacenados una lista de contadores. Queremos encontrar los valores MIN / MAX en cada mes a lo largo de los diferentes años. Por ejemplo, para enero sería 10. Y para febrero sería 15. Necesitamos almacenar los resultados en un nuevo 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


El uso de reduce que encontré en mi código implicaba la situación en la que tenía una estructura de clase para la expresión lógica y necesitaba convertir una lista de estos objetos de expresión en una conjunción de las expresiones. Ya tenía una función make_and para crear una conjunción con dos expresiones, así que escribí reduce(make_and,l) . (Sabía que la lista no estaba vacía, de lo contrario habría sido algo como reduce(make_and,l,make_true) .)

Esta es exactamente la razón por la que (algunos) programadores funcionales como reduce (o doblar funciones, como tales funciones se suelen llamar). A menudo ya hay muchas funciones binarias como + , * , min , max , concatenación y, en mi caso, make_and y make_or . Tener una reduce hace que sea trivial levantar estas operaciones a listas (o árboles o lo que sea que tengas, para funciones de pliegue en general).

Por supuesto, si ciertas instancias (como la sum ) se utilizan a menudo, entonces no desea seguir escribiendo reduce . Sin embargo, en lugar de definir la sum con algo de for-loop, puede definirlo con la misma facilidad con reduce .

La legibilidad, como lo mencionaron otros, es de hecho un problema. Podría argumentar, sin embargo, que la única razón por la que las personas encuentran que se reduce menos "claras" es porque no es una función que muchas personas conocen y / o usan.


Encuentra la intersección de N listas 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))

devoluciones:

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

vía: Python - Intersección de dos listas


Estoy escribiendo una función de redacción para un idioma, así que construyo la función compuesta usando reducir junto con mi operador de aplicación.

En pocas palabras, componer toma una lista de funciones para componer en una sola función. Si tengo una operación compleja que se aplica por etapas, quiero poner todo junto de esta manera:

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

De esta manera, puedo aplicarlo a una expresión como esta:

complexop(expression)

Y quiero que sea equivalente a:

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

Ahora, para construir mis objetos internos, quiero que diga:

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

(La clase Lambda crea una función definida por el usuario y Apply crea una aplicación de función).

Ahora, reducir, lamentablemente, se pliega por el camino equivocado, así que terminé usando, grosso modo:

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

Para descubrir qué reduce produce, intente esto en REPL:

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


Los otros usos que he encontrado para él además de + y * fueron con y y, pero ahora tenemos any y all para reemplazar esos casos.

foldl y foldr aparecen mucho en Scheme ...

Aquí hay algunos usos lindos:

Acoplar una lista

Objetivo: convertir [[1, 2, 3], [4, 5], [6, 7, 8]] en [1, 2, 3, 4, 5, 6, 7, 8] .

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

Lista de dígitos a un número

Objetivo: convertir [1, 2, 3, 4, 5, 6, 7, 8] en 12345678 .

Ugly, slow way:

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

Bastante reduce forma:

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


No estoy seguro de si esto es lo que busca, pero puede buscar el código fuente en Google .

Siga el enlace para buscar en ''function: reduce () lang: python'' en la búsqueda de Google Code

A primera vista, los siguientes proyectos usan reduce()

  • MoinMoin
  • Zope
  • Numérico
  • ScientificPython

etc., pero estos no son sorprendentes ya que son grandes proyectos.

La funcionalidad de reducir se puede hacer utilizando la recursión de funciones, que supongo que Guido pensó que era más explícita.

Actualizar:

Dado que la Búsqueda de códigos de Google se suspendió el 15 de enero de 2012, además de volver a las búsquedas regulares de Google, hay algo llamado Recolección de fragmentos de código que parece prometedor. Una cantidad de otros recursos se mencionan en las respuestas a esta pregunta (cerrada) Reemplazo de Google Code Search? .

Actualización 2 (29-mayo-2017):

Una buena fuente para ejemplos de Python (en código fuente abierto) es el Nullege search engine .


Puede reemplazar value = json_obj[''a''][''b''][''c''][''d''][''e''] con:

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

Si ya tiene la ruta a/b/c/.. como una lista. Por ejemplo, Cambiar valores en dict de dictados anidados usando elementos en una lista .


Reducir no está limitado a operaciones escalares; también se puede usar para ordenar cosas en cubos. (Esto es lo que uso reducir para la mayoría de las veces).

Imagine un caso en el que tiene una lista de objetos y desea reorganizarla jerárquicamente en función de las propiedades almacenadas de forma plana en el objeto. En el siguiente ejemplo, produzco una lista de objetos de metadatos relacionados con artículos en un periódico codificado en XML con la función de articles . articles genera una lista de elementos XML, y luego los mapea uno por uno, produciendo objetos que contienen información interesante sobre ellos. En el front end, voy a querer dejar que el usuario explore los artículos por sección / subsección / título. Así que utilizo reduce para tomar la lista de artículos y devolver un solo diccionario que refleje la jerarquía de sección / subsección / artículo.

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

Doy ambas funciones aquí porque creo que muestra cómo el mapa y la reducción pueden complementarse muy bien cuando se trata de objetos. Lo mismo se podría haber logrado con un bucle for, pero pasar un tiempo serio con un lenguaje funcional ha tendido a hacerme pensar en términos de mapa y reducir.

Por cierto, si alguien tiene una mejor manera de establecer propiedades como I''m doing in extract , donde los padres de la propiedad que desea establecer pueden no existir aún, háganmelo saber.


Tengo objetos que representan algún tipo de intervalos de superposición (exones genómicos) y redefiní su intersección usando __and__ :

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

Luego, cuando tengo una colección de ellos (por ejemplo, en el mismo gen), uso

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


Tengo una implementación anterior de Python de pipegrep que usa reduce y el módulo glob para crear una lista de archivos para procesar:

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

Lo encontré útil en ese momento, pero realmente no es necesario, ya que algo similar es igual de bueno, y probablemente más legible

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


Usando reduce () para averiguar si una lista de fechas es consecutiva:

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"


Utilicé reduce para concatenar una lista de vectores de búsqueda PostgreSQL con || operador en 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)


reduce se puede utilizar para obtener la lista con el máximo n-elemento

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

devolvería [5, 2, 5, 7] ya que es la lista con el tercer elemento máximo +


reduce() podría usarse para resolver nombres de puntos (donde eval() es demasiado inseguro para usar):

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


reduce() se puede usar para encontrar el mínimo común múltiplo para 3 o más 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)

Ejemplo:

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


reduce es útil cuando necesita encontrar la unión o intersección de una secuencia de objetos de tipo set .

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

(Aparte de los set reales, un ejemplo de estos son los objetos Q de Django ).

Por otro lado, si está tratando con bool , debe usar any y all :

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


reduce se puede utilizar para admitir búsquedas de atributos encadenados:

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

Por supuesto, esto es equivalente a

self.request.user.email

pero es útil cuando su código necesita aceptar una lista arbitraria de atributos.

(Los atributos encadenados de longitud arbitraria son comunes cuando se trata de modelos de Django).


Composición de funciones : si ya tiene una lista de funciones que le gustaría aplicar en sucesión, 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]

Luego puedes aplicarlos todos consecutivamente con:

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

En este caso, el encadenamiento de métodos puede ser más legible. Pero a veces no es posible, y este tipo de composición puede ser más legible y mantenible que un tipo de sintaxis f1(f2(f3(f4(x)))) .


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


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''] # )}, # []) #}, #[])