Verwandeln Sie "Liste der Tupel" in eine flache Liste oder eine Matrix

80

Bei Sqlite gibt ein Befehl "select..from" die Ergebnisse "output" zurück, die (in Python) gedruckt werden:

>>print output
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]

Es scheint eine Liste von Tupeln zu sein. Ich möchte entweder "Ausgabe" in ein einfaches 1D-Array konvertieren (= Liste in Python, denke ich):

[12.2817, 12.2817, 0, 0, 8.52, 8.52]

oder eine 2x3 Matrix:

12.2817 12.2817
0          0 
8.52     8.52

über "output [i] [j]" zu lesen

Der Befehl "Abflachen" erledigt den Job für die erste Option nicht, und ich habe keine Ahnung für die zweite ... :)

Könnten Sie mir bitte einen Hinweis geben? Etwas schnelles wäre großartig, da echte Daten viel größer sind (hier nur ein einfaches Beispiel).

Garth
quelle
2
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]ist schon eine 3x2 Matrix !? oder habe ich etwas verpasst?
Mouad
Siehe diese Frage
Joel Cornett
1
Für die Rezepte zur Überprüfung der Abflachungsfunktion gibt es bereits ein Beispiel für die Abflachungsfunktion: docs.python.org/library/itertools.html#recipes
mouad
4
[item for sublist in output for item in sublist]funktioniert perfekt und hat den Vorteil, dass Ihre inneren Tupel auch Listen sein können; allgemeiner jede Kombination von inneren und äußeren iterierbaren Werken
Kyss Tao

Antworten:

121

Mit Abstand die schnellste (und kürzeste) Lösung:

list(sum(output, ()))

Etwa 50% schneller als die itertoolsLösung und etwa 70% schneller als die mapLösung.

Joel Cornett
quelle
8
@ Joel schön, aber ich frage mich, wie es funktioniert? list(output[0]+output[1]+output[2])gibt das gewünschte Ergebnis aber list(sum(output))nicht. Warum? Welche "Magie" macht die ()?
Kyss Tao
9
Ok, ich hätte das Handbuch g lesen sollen . Es scheint sum(sequence[, start]): sum addiert startdie Standardeinstellung 0und beginnt nicht erst, sequence[0]wenn sie existiert, und fügt dann den Rest der Elemente hinzu. Tut mir leid, dass ich dich gestört habe.
Kyss Tao
3
Dies ist ein bekanntes Anti-Pattern: Nicht sumzum Verketten von Sequenzen verwenden, sondern zu einem quadratischen Zeitalgorithmus führen. In der Tat wird sich die sumFunktion beschweren, wenn Sie versuchen, dies mit Zeichenfolgen zu tun!
juanpa.arrivillaga
@ juanpa.arrivillaga: vereinbart. Es gibt nur sehr wenige Anwendungsfälle, in denen dies vorzuziehen wäre.
Joel Cornett
8
Ja, schnell aber völlig stumpf. Sie
müssten
42

Listenverständnisansatz, der mit iterierbaren Typen funktioniert und schneller ist als andere hier gezeigte Methoden.

flattened = [item for sublist in l for item in sublist]

list die Liste, die abgeflacht werden soll ( outputim Fall des OP aufgerufen )


Timeit-Tests:

l = list(zip(range(99), range(99)))  # list of tuples to flatten

Listenverständnis

[item for sublist in l for item in sublist]

Zeitergebnis = 7,67 µs ± 129 ns pro Schleife

Liste verlängern () Methode

flattened = []
list(flattened.extend(item) for item in l)

Zeitergebnis = 11 µs ± 433 ns pro Schleife

Summe()

list(sum(l, ()))

Zeitergebnis = 24,2 µs ± 269 ns pro Schleife

Gman
quelle
1
Ich musste dies für einen großen Datensatz verwenden, die Listenverständnismethode war bei weitem die schnellste!
Nbeuchat
Ich habe die .extend-Lösung ein wenig geändert und bin jetzt etwas besser. Überprüfen Sie es auf Ihrer Zeit zu vergleichen
Totoro
22

In Python 3 können Sie die *Syntax verwenden, um eine Liste von Iterables zu reduzieren:

>>> t = [ (1,2), (3,4), (5,6) ]
>>> t
[(1, 2), (3, 4), (5, 6)]
>>> import itertools
>>> list(itertools.chain(*t))
[1, 2, 3, 4, 5, 6]
>>> 
Thruston
quelle
10

Update : Abflachung mit Extend, aber ohne Verständnis und ohne Verwendung von List als Iterator (am schnellsten)

Nachdem dual forich die nächste Antwort auf diese Frage überprüft hatte, die über ein Listenverständnis eine schnellere Lösung ermöglichte, nahm ich eine kleine Änderung vor und jetzt ist die Leistung besser. Zuerst zog die Ausführung der Liste (...) einen großen Prozentsatz der Zeit in Anspruch und änderte dann eine Liste Das Verständnis für eine einfache Schleife hat sich ebenfalls etwas mehr rasiert.

Die neue Lösung lautet:

l = []
for row in output: l.extend(row)

Älter:

Abflachen mit Karte / Erweitern:

l = []
list(map(l.extend, output))

Abflachung mit Listenverständnis anstelle von Karte

l = []
list(l.extend(row) for row in output)

Einige Zeitpunkte für neue Erweiterungen und die Verbesserung, die durch einfaches Entfernen der Liste (...) für [...] erzielt wurde:

import timeit
t = timeit.timeit
o = "output=list(zip(range(1000000000), range(10000000))); l=[]"
steps_ext = "for row in output: l.extend(row)"
steps_ext_old = "list(l.extend(row) for row in output)"
steps_ext_remove_list = "[l.extend(row) for row in output]"
steps_com = "[item for sublist in output for item in sublist]"

print("new extend:      ", t(steps_ext, setup=o, number=10))
print("old extend w []: ", t(steps_ext_remove_list, setup=o, number=10))
print("comprehension:   ", t(steps_com, setup=o, number=10,))
print("old extend:      ", t(steps_ext_old, setup=o, number=10))

>>> new extend:       4.502427191007882
>>> old extend w []:  5.281140706967562
>>> comprehension:    5.54302118299529
>>> old extend:       6.840151469223201    
Totoro
quelle
9

verwenden itertoolsKette:

>>> import itertools
>>> list(itertools.chain.from_iterable([(12.2817, 12.2817), (0, 0), (8.52, 8.52)]))
[12.2817, 12.2817, 0, 0, 8.52, 8.52]
Charles Beattie
quelle
7
>>> flat_list = []
>>> nested_list = [(1, 2, 4), (0, 9)]
>>> for a_tuple in nested_list:
...     flat_list.extend(list(a_tuple))
... 
>>> flat_list
[1, 2, 4, 0, 9]
>>> 

Sie können leicht von der Tupelliste zur Einzelliste wechseln, wie oben gezeigt.

Cobie
quelle
7

Oder Sie können die Liste folgendermaßen reduzieren:

reduce(lambda x,y:x+y, map(list, output))
Maria Zverina
quelle
reduce(lambda x,y:x+y, output)scheint direkt in ein langes Tupel zu konvertieren (das in eine Liste konvertiert werden kann). Warum map(list, output)innerhalb des reduce()Anrufs verwenden? Vielleicht stimmt es eher mit der Tatsache überein , dass Tupel unveränderlich und Listen veränderlich sind .
Paul Rougieux
5

Dafür numpywurde sowohl aus Datenstruktur- als auch aus Geschwindigkeitssicht gemacht.

import numpy as np

output = [(12.2817, 12.2817), (0, 0), (8.52, 8.52)]
output_ary = np.array(output)   # this is your matrix 
output_vec = output_ary.ravel() # this is your 1d-array
Joshua Cook
quelle
2

Bei willkürlich verschachtelten Listen (nur für den Fall):

def flatten(lst):
    result = []
    for element in lst: 
        if hasattr(element, '__iter__'):
            result.extend(flatten(element))
        else:
            result.append(element)
    return result

>>> flatten(output)
[12.2817, 12.2817, 0, 0, 8.52, 8.52]
cval
quelle