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