2010-05-23 4 views
14

Eine der großen Stärken von Python und ein paar andere (funktionale) Programmiersprachen sind die list comprehension. Sie ermöglichen es Programmierern, komplexe Ausdrücke in einer Zeile zu schreiben. Sie können zunächst verwirrend sein, aber wenn man sich an die Syntax gewöhnt, ist es viel besser als verschachtelte komplizierte Schleifen.Zeigen Sie mir einige coole Python-Liste Comprehensions

Mit diesem gesagt, bitte teilen Sie mit mir einige der coolsten Verwendungen von List Comprehensions. (Mit cool, ich meine nur nützlich) Es könnte für einen Programmierwettbewerb oder ein Produktionssystem sein.

Zum Beispiel: die Transponierung einer Matrix mat

>>> mat = [ 
...  [1, 2, 3], 
...  [4, 5, 6], 
...  [7, 8, 9], 
...  ] 

>>> [[row[i] for row in mat] for i in [0, 1, 2]] 
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] 

Bitte zu tun, um eine Beschreibung des Ausdrucks ist und wo es verwendet wurde (wenn möglich).

+2

Sie sollten dies als Community-Wiki markieren (bearbeiten Sie Ihre Frage und kreuzen Sie das Kästchen an). –

+1

Beachten Sie, dass Sie, wenn Sie Matrizen darstellen, wahrscheinlich 'numpy' verwenden möchten. –

+4

Für eine schnellere Transponierung von "mat", versuchen Sie 'zip (* mat)'. – PaulMcG

Antwort

8

die Transponierung einer Matrix mat zu tun:

>>> [list(row) for row in zip(*mat)] 
[[1, 4, 7], [2, 5, 8], [3, 6, 9]] 
+3

'map (liste, zip (* mat))' ist ein bisschen terser (aber kein Listenverständnis). – Grumdrig

+1

T erse ist ein Negativ, kein Positiv. Das Vermeiden von map() ist in erster Linie ein großer Vorteil von Listen-Comprehensions. –

+7

@Glenn Das ist eine ziemlich breite Verallgemeinerung. In Anbetracht der Tatsache, dass es sich bei Comprehensions um eine Methode handelt, um Loops auszudrücken, sollten Sie, wenn sie kurz und knapp sind, diese immer in Loops ausdehnen. –

7

Um eine Liste der Listen abflachen:

>>> matrix = [[1,2,3], [4,5,6]] 
>>> [x for row in matrix for x in row] 
[1, 2, 3, 4, 5, 6] 
+4

Oder einfach summieren (Matrix, []). :) –

+0

@Nick, oh Mist - guter Punkt. – Grumdrig

+0

Bedenken Sie, dass die List Comprehension-Version für große Listen effizienter ist als sum (Matrix, []). – David

16

Viele Leute wissen nicht, dass Python ermöglicht es Ihnen, die Ergebnisse zu filtern eines Listenverständnisses mit if:

>>> [i for i in range(10) if i % 2 == 0] 
[0, 2, 4, 6, 8] 
4

Ich benutze dies die ganze Zeit beim Start Tab getrennten Dateien mit optionalen Kommentarzeilen mit einem Hash-Symbol Laden:

data = [line.strip().split("\t") for line in open("my_file.tab") \ 
     if not line.startswith('#')] 

Natürlich wie gut es funktioniert für alle anderen Kommentar und Trennzeichen.

+0

Das ist schrecklich. Zerquetschen Sie nicht viel Code in eine Liste comprehnesion - teilen Sie dies auf. –

+0

@Glenn Maynard: Einverstanden. List Comprehensions sind nicht dazu gedacht, auf diese Weise verwendet zu werden, und auf jeden Fall vereitelt es den Zweck der Iteration von Dateien nach Zeilen, weil Sie nur alles auf einmal lesen und ein Listenverständnis verwenden, um Arbeiten an der Zeile auszuführen. Nicht nur das, aber ... wann ist die Datei geschlossen? Während ich den Vorteil für ein solches Verständnis erkenne, gibt es auch Nachteile, so sei vorsichtig. Das ist fast so schlimm wie ein Aufruf von "malloc" in C ohne einen entsprechenden Aufruf an "free" oder "new" ohne ein zusätzliches "delete" in C++.> _ < – Dustin

+6

Ich stimme nicht zu, dass das schrecklich ist. Ich denke, es ist gut lesbar und genauso lesbar wie die Multiline-Version. – Grumdrig

2

Solange Sie nach funktionalen Programmierung inspiriert Teile von Python sind, ziehen Sie in Betracht, Karte, Filter, reduzieren und zip ---- alle in Python angeboten.

+1

Guidos Erklärung, warum Listenkompressen in der Regel sinnvoller sind als map/filter: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 –

3

Ich habe derzeit mehrere Skripte, die eine Reihe von Punkten in "Ebenen" nach Höhe gruppieren müssen. Die Annahme ist, dass sich die Z-Werte der Punkte lose um bestimmte Werte gruppieren, die den Pegeln entsprechen, mit großen Lücken zwischen den Clustern.

So habe ich die folgende Funktion:

def level_boundaries(zvalues, threshold=10.0): 
    '''Finds all elements z of zvalues such that no other element 
    w of zvalues satisfies z <= w < z+threshold.''' 
    zvals = zvalues[:] 
    zvals.sort() 
    return [zvals[i] for i, (a, b) in enumerate(pairs(zvals)) if b-a >= threshold] 

„Paare“ wird direkt aus dem itertools Modul-Dokumentation entnommen, sondern als Referenz:

def pairs(iterable): 
    'iterable -> (iterable[n], iterable[n+1]) for n=0, 1, 2, ...' 
    from itertools import izip, tee 
    first, second = tee(iterable) 
    second.next() 
    return izip(first, second) 

eine erfundene Verwendungsbeispiel (meine tatsächlichen Datensätze sind ein bisschen zu groß, um als Beispiele zu verwenden):

>>> import random 
>>> z_vals = [100 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> z_vals += [120 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> z_vals += [140 + random.uniform(-1.5,1.5) for n in range(10)] 
>>> random.shuffle(z_vals) 
>>> z_vals 
[141.33225473458657, 121.1713952666894, 119.40476193163271, 121.09926601186737, 119.63057973814858, 100.09095882968982, 99.226542624083109, 98.845285642062763, 120.90864911044898, 118.65196386994897, 98.902094334035326, 121.2741094217216, 101.18463497862281, 138.93502941970601, 120.71184773326806, 139.15404600347946, 139.56377827641663, 119.28279815624718, 99.338144106822554, 139.05438770927282, 138.95405784704622, 119.54614935118973, 139.9354467277665, 139.47260445000273, 100.02478729763811, 101.34605205591622, 138.97315450408186, 99.186025111246295, 140.53885845445572, 99.893009827114568] 
>>> level_boundaries(z_vals) 
[101.34605205591622, 121.2741094217216] 
+0

Können Sie den möglichen Import für zvalues ​​anzeigen? – christangrant

+0

Ich habe ein Beispiel hinzugefügt, wenn Sie das gemeint haben. –

9

Ich benutze oft compre hensions dicts zu konstruieren:

my_dict = dict((k, some_func(k)) for k in input_list) 

Hinweis Python 3 dict Comprehensions hat, so wird daraus:

my_dict = {k:some_func(k) for k in input_list} 

Für CSV-ähnliche Daten aus einer Liste von Tupeln Konstruktion:

data = "\n".join(",".join(x) for x in input) 

Nicht eigentlich ein Listenverständnis, aber immer noch nützlich: Erzeuge eine Liste von Bereichen aus einer Liste von 'Schnittpunkten':

ranges = zip(cuts, cuts[1:]) 
+0

Nicht eine davon ist ein Listenverständnis. Das sind Generatorausdrücke. –

+0

Ein Listenverständnis ist jedoch nur ein Spezialfall eines Genexp. Ich kann eckige Klammern um sie legen, wenn das dich glücklich machen würde, aber ich nehme an, dass das OP an der Technik interessiert war, nicht an den Details. –

5

Wenn „cool“ bedeutet verrückt, Ich mag dieses:

def cointoss(n,t): 
    return (lambda a:"\n".join(str(i)+":\t"+"*"*a.count(i) for i in range(min(a),max(a)+1)))([sum(randint(0,1) for _ in range(n)) for __ in range(t)]) 

>>> print cointoss(20,100) 
3: ** 
4: *** 
5: ** 
6: ***** 
7: ******* 
8: ********* 
9: ********* 
10: ******************** 
11: ***************** 
12: ********* 
13: ***** 
14: ********* 
15: * 
16: ** 

n und t die Anzahl der Münzwürfen pro Test steuern und die Anzahl der Male der Test durchgeführt wird, und die Verteilung aufgetragen ist.