Python'da less () işlevini kullanan herhangi bir yararlı koda sahip olan var mı? Örneklerde gördüğümüz normal + ve * dışında herhangi bir kod var mı?
Bkz Python 3000) (kaderin azaltmak GvR tarafından
Python'da less () işlevini kullanan herhangi bir yararlı koda sahip olan var mı? Örneklerde gördüğümüz normal + ve * dışında herhangi bir kod var mı?
Bkz Python 3000) (kaderin azaltmak GvR tarafından
Yanıtlar:
+ Ve * dışında bulduğum diğer kullanımlar, ve ve veya ile idi, ancak şimdi bu durumlara sahibiz any
ve all
bunları değiştirmeliyiz.
foldl
ve foldr
Scheme'de sık sık ortaya çıkıyor ...
İşte bazı sevimli kullanımlar:
Listeyi düzleştir
Hedef: [[1, 2, 3], [4, 5], [6, 7, 8]]
dönüşmek [1, 2, 3, 4, 5, 6, 7, 8]
.
reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])
Bir numaranın rakam listesi
Hedef: [1, 2, 3, 4, 5, 6, 7, 8]
dönüşmek 12345678
.
Çirkin, yavaş yol:
int("".join(map(str, [1,2,3,4,5,6,7,8])))
Güzel reduce
yol:
reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
timeit.repeat('int("".join(map(str, digit_list)))', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)
~ 0.09 saniye 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)
sürer, 0.36 saniye sürer (yaklaşık 4 kat daha yavaş). Temelde 10 ile çarpma, liste büyüdüğünde pahalı hale gelirken, int'den str'ye ve birleştirme ucuz kalır.
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 sn, 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 sn ve basamakları str yöntemine dönüştürmek 0,16 sn sürmektedir.
reduce()
3 veya daha fazla sayı için En az ortak katı bulmak için kullanılabilir :
#!/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)
Misal:
>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
lcm
ikinci satırında?
Verilen N listenin kesişimini bulun:
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))
İadeler:
result = set([3, 4, 5])
Kodumda reduce
bulduğum kullanım, mantık ifadesi için bazı sınıf yapısına sahip olduğum durumu içeriyordu ve bu ifade nesnelerinin bir listesini ifadelerin bir birleşimine dönüştürmem gerekiyordu. Zaten make_and
iki ifade verilen bir birleşim yaratmak için bir fonksiyonum vardı , bu yüzden yazdım reduce(make_and,l)
. (Listenin boş olmadığını biliyordum; aksi takdirde şöyle bir şey olurdureduce(make_and,l,make_true)
.)
Bu tam olarak (bazı) işlevsel programcıların benzer reduce
(veya bu tür işlevler genellikle çağrıldığı için işlevleri katlama ) nedenidir . Orada gibi zaten birçok ikili fonksiyonlar genellikle +
, *
, min
, max
, birleştirmek ve benim durumumda, make_and
ve make_or
. Sahip olmakreduce
bu işlemleri listelere (veya ağaçlara veya genel olarak katlama işlevleri için olduğunuz her şeye) kaldırmayı önemsiz hale getirir.
Elbette sum
, sık sık bazı örnekler (örneğin ) kullanılıyorsa, yazmaya devam etmek istemezsiniz reduce
. Ancak, bunun yerine tanımlanması sum
bazıları için-döngü ile, sen yapabilirsiniz aynı kolaylıkla ile tanımlamak reduce
.
Başkalarının da belirttiği gibi okunabilirlik gerçekten bir sorundur. Ancak, insanların reduce
daha az "net" bulmalarının tek sebebinin , bunun birçok insanın bildiği ve / veya kullandığı bir işlev olmaması olduğunu iddia edebilirsiniz.
and
operatörün kısa devre davranışından yararlanabilirsiniz : L and reduce(make_and, L)
bu durumda boş listenin geri
İşlev bileşimi : Art arda uygulamak istediğiniz işlevlerin bir listesine zaten sahipseniz, örneğin:
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]
Daha sonra hepsini arka arkaya uygulayabilirsiniz:
>>> 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'
Bu durumda, yöntem zincirleme daha okunaklı olabilir. Ancak bazen bu mümkün değildir ve bu tür bir kompozisyon, bir f1(f2(f3(f4(x))))
tür sözdiziminden daha okunabilir ve sürdürülebilir olabilir .
Şununla değiştirebilirsiniz value = json_obj['a']['b']['c']['d']['e']
:
value = reduce(dict.__getitem__, 'abcde', json_obj)
Zaten a/b/c/..
bir liste olarak yolunuz varsa . Örneğin, bir listedeki öğeleri kullanarak yuvalanmış diktlerdeki değerleri değiştirin .
@Blair Conrad: Glob'unuzu / azaltmanızı toplamı kullanarak da uygulayabilirsiniz, örneğin:
files = sum([glob.glob(f) for f in args], [])
Bu, iki örnekten herhangi birinden daha az ayrıntılı, mükemmel bir şekilde Pythonic ve hala yalnızca bir kod satırı.
Bu nedenle, orijinal soruyu yanıtlamak için, kişisel olarak azaltmayı kullanmaktan kaçınmaya çalışıyorum çünkü asla gerçekten gerekli değil ve diğer yaklaşımlardan daha az net buluyorum. Ancak, bazı insanlar anlamaları listelemeye alışıyor ve bunu tercih ediyor (özellikle Haskell programcıları). Ancak, azaltma açısından bir sorun hakkında zaten düşünmüyorsanız, muhtemelen onu kullanma konusunda endişelenmenize gerek yoktur.
sum
ve reduce
kuadratik davranışa yol açar. Bu doğrusal zamanda yapılabilir: files = chain.from_iterable(imap(iglob, args))
. Glob () 'un bir diske erişmesi için geçen süre nedeniyle bu durumda muhtemelen önemi yoktur.
reduce
zincirleme öznitelik aramalarını desteklemek için kullanılabilir:
reduce(getattr, ('request', 'user', 'email'), self)
Tabii ki bu eşdeğerdir
self.request.user.email
ancak kodunuzun rastgele bir öznitelik listesini kabul etmesi gerektiğinde kullanışlıdır.
(Django modelleriyle uğraşırken rastgele uzunlukta zincirli öznitelikler yaygındır.)
reduce
benzer set
nesneler dizisinin birleşimini veya kesişimini bulmanız gerektiğinde kullanışlıdır .
>>> reduce(operator.or_, ({1}, {1, 2}, {1, 3})) # union
{1, 2, 3}
>>> reduce(operator.and_, ({1}, {1, 2}, {1, 3})) # intersection
{1}
(Gerçek ' set
ler dışında bunlara bir örnek Django'nun Q nesneleridir. .)
Öte yandan, bool
s ile uğraşıyorsanız , any
ve kullanmalısınız all
:
>>> any((True, False, True))
True
Kodumu oluşturduktan sonra, azaltmayı kullandığım tek şey faktöriyel hesaplamaktı:
reduce(operator.mul, xrange(1, x+1) or (1,))
Bir dil için bir oluşturma işlevi yazıyorum, bu nedenle oluşturulan işlevi, uygulama operatörümle birlikte azaltmayı kullanarak oluşturuyorum.
Özetle, compose tek bir işlevde oluşturmak için işlevlerin bir listesini alır. Aşamalı olarak uygulanan karmaşık bir işlemim varsa hepsini bir araya getirmek istiyorum:
complexop = compose(stage4, stage3, stage2, stage1)
Bu şekilde, bunu şöyle bir ifadeye uygulayabilirim:
complexop(expression)
Ve şuna eşdeğer olmasını istiyorum:
stage4(stage3(stage2(stage1(expression))))
Şimdi, iç nesnelerimi oluşturmak için şunu söylemesini istiyorum:
Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x'))))))
(Lambda sınıfı, kullanıcı tanımlı bir işlev oluşturur ve Apply, bir işlev uygulaması oluşturur.)
Şimdi, azaltın, maalesef yanlış şekilde katlayın, bu yüzden kabaca şunu kullanarak yaralandım:
reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')]))
Hangi azalmanın ürettiğini bulmak için, REPL'de şunları deneyin:
reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))
compose = lambda *func: lambda arg: reduce(lambda x, f: f(x), reversed(funcs), arg)
için performans testleri için fonksiyonlar tüm olası kombinasyonları oluşturmak.
azaltma, maksimum n'inci elemanı içeren listeyi elde etmek için kullanılabilir
reduce(lambda x,y: x if x[2] > y[2] else y,[[1,2,3,4],[5,2,5,7],[1,6,0,2]])
en fazla 3. eleman içeren liste olduğu için [5, 2, 5, 7] döndürür +
Azaltma, skaler işlemlerle sınırlı değildir; şeyleri kovalara ayırmak için de kullanılabilir. (Bu, en sık kullandığım şeydir).
Bir nesne listesine sahip olduğunuz ve nesnede düz olarak depolanan özelliklere dayalı olarak bunu hiyerarşik olarak yeniden düzenlemek istediğiniz bir durum düşünün. Aşağıdaki örnekte, articles
işlevle XML kodlu bir gazetedeki makalelerle ilgili meta veri nesnelerinin bir listesini oluşturuyorum . articles
XML öğelerinin bir listesini oluşturur ve ardından bunların içinden birer birer eşleyerek, kendileriyle ilgili ilginç bilgiler içeren nesneler üretir. Ön uçta, kullanıcının makaleleri bölüm / alt bölüm / başlığa göre taramasına izin vermek istiyorum. Bu yüzden reduce
makalelerin listesini alıp bölüm / alt bölüm / makale hiyerarşisini yansıtan tek bir sözlüğü döndürmek için kullanıyorum.
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, {})
Burada her iki işlevi de veriyorum çünkü bu, eşleme ve azaltmanın nesnelerle uğraşırken birbirlerini nasıl güzel bir şekilde tamamlayabileceğini gösterdiğini düşünüyorum. Aynı şey bir for döngüsü ile de başarılabilirdi, ama işlevsel bir dille ciddi zaman geçirmek, beni harita açısından düşünmeye ve azaltmaya yöneltti.
Bu arada, benim yaptığım gibi mülkleri ayarlamanın daha iyi bir yolu varsa, ayarlamak extract
istediğiniz mülkün ebeveynlerinin henüz mevcut olmadığı durumlarda lütfen bana bildirin.
Peşinde olduğun şeyin bu olup olmadığından emin değilim ama Google'da kaynak kodunu arayabilirsin .
'Function: below () lang: python' ile ilgili arama için bağlantıyı takip edinGoogle Code aramasında ilgili
İlk bakışta aşağıdaki projeler şunu kullanır: reduce()
vb. ama sonra bunlar büyük projeler oldukları için pek şaşırtıcı değil.
Azaltma işlevselliği, Guido'nun daha açık bulduğunu düşündüğüm işlev özyineleme kullanılarak yapılabilir.
Güncelleme:
Google'ın Kod Arama 15 Ocak 2012'de sona erdiğinden, normal Google aramalarına geri dönmenin yanı sıra, umut verici görünen Kod Parçacıkları Koleksiyonu adlı bir şey var . Bu (kapalı) sorunun yanıtlarında bir dizi başka kaynaktan bahsedilmiştir Google Code Search’ün Değiştirilmesi?.
Güncelleme 2 (29-Mayıs-2017):
Python örnekleri için iyi bir kaynak (açık kaynak kodunda) Nullege arama motorudur .
for
döngü.
lang:python "reduce("
tanımları bulacaktır reduce
.
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']
# )},
# [])
#},
#[])
Ben kullanılan reduce
PostgreSQL arama vektörlerin bir listesini bitiştirmek ile ||
sqlalchemy aranabilir operatör:
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)
İşlenecek dosyaların bir listesini oluşturmak için azaltma ve glob modülünü kullanan eski bir pipegrep Python uygulamasına sahibim :
files = []
files.extend(reduce(lambda x, y: x + y, map(glob.glob, args)))
O sırada kullanışlı buldum, ancak gerçekten gerekli değil, çünkü benzer bir şey aynı derecede iyi ve muhtemelen daha okunabilir
files = []
for f in args:
files.extend(glob.glob(f))
files = [glob.glob(f) for f in args]
itertools
kullanarak içe aktarmanızı ve ardından şunu yazmanızı öneririm : (Ve bu sefer kodu göndermeden önce test ettim ve bunun doğru çalıştığını biliyorum.)flatten()
files = flatten(glob.glob(f) for f in args)
files = chain.from_iterable(imap(iglob, args))
nerede chain
, imap
gelmektedir itertools
modül ve glob.iglob
bir desen halinde yararlıdır args
birkaç dizinleri dosyaları oluşturabilir.
Sayaçların bir listesi olarak saklanan bazı yıllık istatistik verileri olduğunu varsayalım. MİN / MAKS değerlerini farklı yıllarda her ay bulmak istiyoruz. Örneğin, Ocak için 10, Şubat için 15 olacaktır. Sonuçları yeni bir Sayaçta saklamamız gerekir.
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
Bir tür örtüşen aralıkları (genomik eksonlar) temsil eden nesnelerim var ve bunları kullanarak kesişimlerini yeniden tanımladım __and__
:
class Exon:
def __init__(self):
...
def __and__(self,other):
...
length = self.length + other.length # (e.g.)
return self.__class__(...length,...)
Sonra onlardan bir koleksiyonum olduğunda (örneğin, aynı gende), kullanıyorum
intersection = reduce(lambda x,y: x&y, exons)
Az önce reduce
: ayırıcıyı kaldırmadan dizeyi ayırmanın yararlı kullanımını buldum . Kod tamamen Programatik Olarak Konuşma blogundan alınmıştır. İşte kod:
reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem == "\n" else acc + [elem], re.split("(\n)", "a\nb\nc\n"), [])
İşte sonuç:
['a\n', 'b\n', 'c\n', '']
SO'daki popüler yanıtın sahip olmadığı uç durumları ele aldığına dikkat edin. Daha ayrıntılı açıklama için sizi orijinal blog gönderisine yönlendiriyorum.
Bir tarih listesinin ardışık olup olmadığını öğrenmek için azaltmak () kullanın:
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"
from functools import reduce
aynı kodun hem Python 2 hem de 3 üzerinde çalışmasına izin verir.