List Comprehensions in Python: effiziente Auswahl in einer Liste

8

Nehmen wir an, ich habe eine Liste von Elementen, und ich möchte nur einige davon nach einer bestimmten Funktion auswählen (zum Beispiel eine Entfernung zu einem anderen Element).

Ich möchte als Ergebnis eine Liste von Tupel haben, mit der Entfernung und dem Element. Also, ich schrieb den folgenden Code

%Vor%

Aber myFunction ist eine sehr zeitraubende Funktion und die originalList ziemlich groß. Auf diese Weise wird myFunction zweimal für jedes ausgewählte Element aufgerufen.

Also, gibt es eine Möglichkeit, das zu vermeiden?

Ich habe zwei andere Möglichkeiten, aber sie sind nicht so gut:

  1. der erste, ist das Erstellen der ungefilterte Liste

    %Vor%

    und dann sortiere es

    %Vor%

    aber in diesem Fall verdopple ich meine originalList und vergeude etwas Speicher (Die Liste könnte ziemlich groß sein - mehr als 10.000 Elemente)

  2. Der zweite ist knifflig und nicht sehr pythonisch, aber effizient (das Beste, was wir tun können, da die Funktion einmal pro Element evaluiert werden sollte). myFunction speichert es zuletzt Ergebnis in einer globalen Variablen ( lastResult zum Beispiel), und dieser Wert wird in der wiederverwendet Listenverständnis

    %Vor%

Haben Sie eine bessere Idee, dies auf effiziente und pythonische Weise zu erreichen?

Danke für deine Antworten.

    
ThibThib 03.08.2009, 14:30
quelle

7 Antworten

9

Sicher, der Unterschied zwischen den beiden folgenden:

%Vor%

und das:

%Vor%

ist, dass der erste die Liste im Speicher erzeugt, während der zweite ein neuer Generator ist, mit fauler Auswertung.

Schreiben Sie also einfach die "ungefilterte" Liste als Generator. Hier ist Ihr Code, mit dem Generator inline:

%Vor%

Beachten Sie, dass Sie keinen Unterschied im Ausdruck von den beiden sehen werden, aber wenn Sie sich die Speicherauslastung ansehen sollten, wird die zweite Anweisung, die auskommentiert ist, mehr Speicher verwenden.

Um Ihren Code in Ihrer Frage einfach zu ändern, schreiben Sie ihn wie folgt ungefiltert:

%Vor%     
Lasse Vågsæther Karlsen 03.08.2009, 14:38
quelle
3

Benutze kein Listenverständnis; eine normale for-Schleife ist hier in Ordnung.

    
Kiv 03.08.2009 14:39
quelle
3

Berechnen Sie einfach vorher die Abstände und filtern Sie dann die Ergebnisse:

%Vor%

Hinweis: Anstatt eine neue Liste zu erstellen, verwende ich einen Generator-Ausdruck, um die Abstand / Element-Paare zu erstellen.

    
unbeknown 03.08.2009 14:42
quelle
1

Lasse V. Karlsen hat eine ausgezeichnete Antwort auf Ihre Frage.

Wenn Ihre Distanzberechnung langsam ist, dann sind Ihre Elemente Polylinien, oder etwas ähnliches, richtig?

Es gibt viele Möglichkeiten, es schneller zu machen:

  • Wenn der Abstand zwischen Begrenzungsrahmen von Objekten & gt; X, dann folgt, dass der Abstand zwischen diesen Objekten & gt; X. Sie müssen also nur die Entfernung zwischen Begrenzungsfeldern berechnen.

  • Wenn Sie alle Objekte, die weniger als X von Objekt A entfernt sind, verwenden möchten, sind nur Objekte, deren Begrenzungsrechteck das um X vergrößerte Begrenzungsfeld von A schneidet, mögliche Übereinstimmungen.

Wenn Sie den zweiten Punkt verwenden, können Sie wahrscheinlich viele Kandidatenübereinstimmungen löschen und die langsame Berechnung nur bei Bedarf durchführen.

Begrenzungsrahmen müssen vorher zwischengespeichert werden.

Wenn Sie wirklich viele Objekte haben, können Sie auch die Raumpartitionierung verwenden ...

Oder konvexe umschließende Polys, wenn Sie in 3D sind

    
peufeu 04.08.2009 09:37
quelle
0

Anstatt eine globale Variable wie in Option 2 zu verwenden, können Sie sich darauf verlassen, dass in Python Parameter nach Objekt übergeben werden - das heißt, das Objekt, das an Ihre myFunction -Funktion übergeben wird, ist das gleiche Objekt als das in der Liste (das ist nicht genau dasselbe wie Anruf durch Verweis, aber es ist nahe genug).

Wenn Ihre myFunction also ein Attribut für das Objekt setzt - etwa _result - könnten Sie nach diesem Attribut filtern:

%Vor%

und Ihre myFunction könnte so aussehen:

%Vor%     
Daniel Roseman 03.08.2009 14:42
quelle
0

Was ist mit Option 1 falsch?

"Dupliziere meine OriginalList und verschwende etwas Speicher (die Liste könnte ziemlich groß sein - mehr als 10.000 Elemente)"

10.000 Elemente sind nur 10.000 Zeiger auf Tupel, die auf existierende Objekte zeigen. Denken Sie etwa 160.000 an Speicher. Es lohnt sich nicht, darüber zu reden.

    
S.Lott 03.08.2009 14:42
quelle
0

Einige Optionen:

  • Verwenden Sie die Memo-Erstellung
  • Verwenden Sie eine normale for-Schleife
  • Erstellen Sie eine ungefilterte Liste und filtern Sie sie dann (Ihre Option 1). Die "verschwendete" Erinnerung wird vom GC sehr schnell zurückgewonnen - Sie müssen sich keine Gedanken darüber machen.
Joe Gauterin 03.08.2009 14:52
quelle

Tags und Links