2014-10-31 5 views
10

Ich habe eine Methode, die eine Liste nehmen und geben ein ObjektPython: Wie man lokale Variable im Listenverstehen einstellt?

# input a list, returns an object 
def map_to_obj(lst): 
    a_list = f(lst) 
    return a_list[0] if a_list else None 

ich eine Liste zu bekommen, die alle abgebildeten Elemente enthält, die nicht None ist.

So:

v_list = [v1, v2, v3, v4] 

[map_to_obj(v) for v in v_list if map_to_obj(v)] 

Aber es scheint nicht gut, die map_to_obj Methode zweimal in der Liste das Verständnis zu nennen.

Gibt es eine Möglichkeit, lokale Variablen im Listenverständnis zu haben, damit sie eine bessere Leistung haben?

Oder optimiert der Compiler es automatisch? Hier

ist das, was ich will:

(sml like) 
[let mapped = map_to_obj(v) in for v in v_list if mapped end] 

Antwort

33

Verwenden verschachtelte Liste Verständnis:

[x for x in [map_to_obj(v) for v in v_list] if x]

oder noch besser, ein Listenverständnis um ein Generator Ausdruck:

[x for x in (map_to_obj(v) for v in v_list) if x]

+3

Es ist eine gute Antwort. Antworten sollten keine Fragezeichen haben. – Paul

+0

Es ist eine gute Antwort, und natürlich ist es das gleiche wie [behzad] (http://stackoverflow.com/users/625914/behzad-nouri) 's, mit List Comprehensions anstelle von 'map' und' filter' ... Ich werde upvote, wie ich mochte [Lying Dog] (http: // stackoverflow.com/users/4134826/lying-dog) übersetzt "Filter" in Bezug auf l-c, aber das OP kann eine dieser Antworten entweder als gute, nützliche Antworten genehmigen. – gboffi

+2

Das innere Verständnis sollte ein Generatorausdruck sein. Es ist nicht nötig, die gesamte Liste zu erstellen und erst dann die leeren Gegenstände wegzuwerfen, um eine weitere Liste zu erstellen. –

3

Sie können mit Python Neuberechnung vermeiden Einbau-filter:

list(filter(lambda t: t is not None, map(map_to_obj, v_list))) 
+0

Aber das iteriert auch die Liste zweimal ... –

+0

Gibt es eine One-Iteration-Lösung? –

+0

@HaoTan nicht in Python 3; In Python 3 gibt 'map' ein Map-Objekt zurück, nicht eine Liste, und' filter' gibt ein Filterobjekt zurück; also, _chain_ die Funktionen, ohne Zwischenlisten zu machen. –

0

Liste Comprehensions ist für die einfachen Fälle in Ordnung, aber manchmal eine einfache alte for Schleife ist die einfachste Lösung:

other_list = [] 
for v in v_list: 
    obj = map_to_obj(v) 
    if obj: 
     other_list.append(obj) 

Nun, wenn Sie wirklich eine Liste comp wollen und nicht wollen eine tmp-Liste erstellen, können Sie die Iterator Versionen von filter und map verwenden:

import itertools as it 
result = list(it.ifilter(None, it.imap(map_to_obj, v_list))) 

oder einfacher:

import itertools as it 
result = filter(None, it.imap(map_to_obj, v_list))) 

Die Iterator Versionen bauen keine temporäre Liste, verwenden sie faul Auswertung.

def map_and_append(lst, v): 
    mapped = map_to_obj(v) 
    if mapped is not None: 
     lst.append(mapped) 
    return lst 

reduce(map_and_append, v_list, []) 

Wie über die Leistung dieser:

0

Ich habe eine Art der Verwendung reduce herausgefunden?

+0

Sie können das' timeit'-Modul verwenden, um die verschiedenen Lösungen zu zeitreichen, aber Ihr oberes Snippet ist ein willkürlich überkomplizierte Art und Weise, eine sehr einfache Sache zu tun - und ich bezweifle, dass es entweder schneller oder platzsparender sein wird als die einfache alte for-Schleife oder die Filter/Imap-Lösungen ... –

+0

@Bruno Ich mag Ihre «overcomplexified»! – gboffi

+0

Wenn ich auf die Antworten von no itertools schaue, ungeachtet der Leistung, wage ich zu sagen, dass [Lying Dogs] (http://stackoverflow.com/a/26672589/2749397) am ausdrucksstärksten ist und daher am lesbarsten ist. Und was ist mit Leistung? Nun, ich weiß nicht, wieviel CPU du in deinen 'f (lst)' calls verbringst, aber das 'None' auf die eine oder andere Weise zu entfernen ist unwahrscheinlich, das ganze Bild zu ändern. – gboffi

Verwandte Themen