2010-09-13 14 views
7

Bazı listenizde L varsa ve bazı boolean işlevlerine göre P iki listeye ayırmak istediğinizi varsayalım. Yani, l öğesinin P(l) öğesinin bir listesi ve P(l) öğesinin yanlış olduğu başka bir listenin bir listesini istiyorsunuz.Bir listeyi ateşkes ve fals'lere filtrelemek için işlevsel bir programlama deyimi var mı?

ben şöyle Python bu uygulayabilirsiniz:

def multifilter(pred,seq): 
    trues,falses = [],[] 
    for x in seq: 
     if pred(x): 
      trues.append(x) 
     else: 
      falses.append(x) 
    return trues,falses 

Benim soru: Bu işlevi gören fonksiyonel programlama deyim var mı?

cevap

9

:

daha işlev çağrıları istemedikçe, fonksiyonel-programlama tarzı yüksekliğini var
from itertools import tee, filterfalse 
def partition(pred, iterable): 
    t1, t2 = tee(iterable) 
    return filterfalse(pred, t1), filter(pred, t2) 
+0

Bunu beğendim, yaptığımdan daha genel. – wheaties

+0

Bu muhtemelen Python'da yapmanın en iyi yoludur. jeneratörler ile de çalışır. sadece kusur tek-liner = P değil. Ama bunu biraz kötüye kullanmadan yapabilirdiniz: lambda pred, iterable: tuple (f (ön, t) f, t zip ([filter, filterfalse], tee (iterable))). bu değil .. o herhangi bir şekilde daha iyi – Claudiu

+0

Ben sadece yakın zamanda itertools.tee 'kullanılmış değildi düşünüyorum ... teşekkürler! – perimosocordiae

1

Elbette var. Aslında, Python'da zaten bulunan bir tane var. Groupby işlevi için itertools'un altına bakın. Ancak, listeyi ilk önce işlev türüne göre sıralamanız gerekecektir. Eminim ki bu sizin peşinde olmadığınız şey değil ama bir başlangıç.

Ben hep sen aracılığıyla ifilter için soruyorsun uyguladık: Bir o 2 öğeli tanımlama grubu sonucunu üretir azaltmak ile yapabilirsiniz

def multifilter(pred, arg): 
    return ifilter(pred, arg), ifilter(lambda x: !pred(x), arg) 
+0

Evet, "groupby" ve "ifilter" fikirleri işe yarayacak, ancak tek geçişli bir işlem olması ve daha karmaşık olmasını sağlamak için beni kirli hissettiriyorlar. – perimosocordiae

+0

Teknik olarak, jeneratörler/yineleyiciler tek geçişli olduğu için, bir jeneratör veya başka bir yineleyiciyi "arg" olarak iletmeye çalışırsanız bu durum kesilir. Tek bir jeneratörden iki öğe grubu oluşturmak için 'itertools.tee' kullanmanız gerekir. – Amber

+0

@Amber Yup, Alex B'nin cevabını gördü. Cevabımı değiştirecek olsaydım, cevabımın cevabından daha yüksek bir şansa sahip olabileceğine dair bir şans var. Bunu istemiyorum. – wheaties

2

.

reduce(lambda x,y: (x[0]+[y],x[1]) if somefunc(y) else (x[0],x[1]+y), somelist, ([],[])) 

2-tuple; İlk kısım, somefunc() döndürme True, ikincisi kalan öğelerin bir listesidir.

+0

Aha, neler olduğunu anlamaya bir saniye sürdü, ama hoşuma gitti. – perimosocordiae

+0

zeki, ama oldukça verimsiz - çok sayıda küçük liste oluşturuyor ve çok sayıda liste birleştirme yapıyorsunuz – Claudiu

3

Hoogle bunun için iyi bir araçtır. Bir işlev tipi girebilir ve bu türdeki tüm işlevleri görebilirsiniz. Bu durumda giriş olarak ihtiyacımız var: a'un bir listesi ve a alan ve bir boole döndüren bir işlev ve çıkış a listelerinin bir çiftidir. Haskell sözdiziminde (a -> Bool) -> [a] -> ([a], [a]). Buradan ilgili işlevin partition olduğunu görüyoruz. Uygulama: Python

partition p xs == (filter p xs, filter (not . p) xs) 

: Ya bu hızlıdır

partition = lambda p, xs: (filter(p, xs), filter(lambda f: not p(f), xs)) 

ama asimetrik var neden biraz daha çirkin:

partition = lambda p, xs: (filter(p, xs), [z for z in xs if not p(z)]) 

Bu size gereken hesaplamaların iki katı sayıda iş yapar yine de, ama mutasyonunuz yoksa bunu yapmanız gerektiğini düşünüyorum. itertools örneklerden

+0

OP'nin kendi sorularını Python olarak etiketlediğini, bu nedenle bu dilde bir çözüm aramayabileceğini veya aramayabileceğini unutmayın. İyi genel cevap olsa da. – Amber

+0

@Amber: evet, iyi nokta. Bunu fark ettim ki bir Python çevirisi ekledim. – Claudiu

+0

Vay, Daha önce Hoogle'u görmemiştim. Bu harika! – perimosocordiae

0
trues = [x for x in seq if pred(x)] 
falses = [x for x in seq if not pred(x)] 

.

İlgili konular