Es tut mir leid für den langen Beitrag. Könnte mir bitte jemand beim Zusammenführen von zwei verschachtelten Listen unterschiedlicher Länge helfen? Es gibt unzählige Beispiele für das "elementweise" Verbinden von Listen bei Google und SO, aber keines davon scheint meinen Fall genau abzudecken. Ich muss dies tausende Male tun, auf Listen, die jeweils ~ 1 Million Zeilen lang sind.
Eine Liste hat das Format:
shortdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
["2015.01.01 22:00:04","1.21032","1.21035","1.21034","1.21034"],
["2015.01.01 22:00:06","1.21021","1.21027","1.21028","1.21028"],
...
["2015.01.01 22:00:56","1.21040","1.21038","1.21039","1.21039"],
["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
["2015.01.01 22:01:04","1.21045","1.21034","1.21036","1.21032"],
...
]
Die andere Liste hat das Format:
longdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
...
]
Ich möchte die Unterlisten zusammenfügen, so dass die Ausgabe eine Liste der kombinierten Unterlisten ist, möglicherweise mit einem Auffüllen von leeren Spalten, d. H. So etwas wie:
combineddata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:04","1.21032","1.21035","1.21034","1.21034"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:06","1.21021","1.21027","1.21028","1.21028"],
...
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "", "2015.01.01 22:00:56","1.21040","1.21038","1.21039","1.21039"],
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038", "", "",["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "","", "2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "", "", "2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035", "", "", "2015.01.01 22:01:04","1.21045","1.21034","1.21036","1.21032"],
...
]
Die 'Minuten-Daten' werden in jeder Zeile absichtlich wiederholt, da sie für zeilenweise Berechnungen benötigt werden.
Wenn ich ein klares Listenverständnis mache, funktioniert es nicht, weil die Listen unterschiedlich lang sind - es gibt offensichtlich weit mehr 2-Sekunden-Daten als 1-Minuten-Daten.
Ich dachte dann, ich könnte die Elemente der 1-Minuten-Daten duplizieren, um sie auf die gleiche Länge wie die 2s-Daten zu bringen, so dass ich dann einfach die beiden Listen zusammen komprimieren könnte. Dies scheiterte auch spektakulär:
expandedlist = [[x] * n for x in longdata]
Aber ich habe ein falsches Format, z. für n = 3 zur Demonstration (statt 30!):
[[['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038']], [['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037']],
...
Es gibt also etwas zu viel Verschachtelung. Ich habe versucht, die äußeren '[]' Zeichen zu entfernen, Liste (x) anstelle von [x] zu versuchen und äußere Klammern '(' zu verwenden, von denen keine dazu führt, dass etwas im beabsichtigten Format mit den 2s-Daten komprimiert wird.
Ich dachte, ich könnte vielleicht itertools.izip_longest () mit einem Füllwert verwenden und die 2s-Zeilen mit den erforderlichen Ein-Minuten-Daten füllen, so etwas wie:
combinedlist = list(itertools.izip_longest(longdata, shortdata, fillvalue=<something goes here>))
print combinedlist
Ich verstehe die Syntax nicht wirklich und selbst das Füllen des Dateianwerts mit einer einfachen Zeichenfolge zeigt, dass es der beabsichtigten Ausgabe nicht sehr ähnlich sieht. Ich bekomme:
[(['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038'], ['2015.01.01 22:00:00', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:01:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:02', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:02:00', '1.2105', '1.2105', '1.2105', '1.2105'], ['2015.01.01 22:00:04', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:03:00', '1.21043', '1.21043', '1.21043', '1.21043'], ['2015.01.01 22:00:06', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:04:00', '1.21049', '1.21049', '1.21049', '1.21049'], ['2015.01.01 22:00:08', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:05:00', '1.21043', '1.21043', '1.21038', '1.21038'], ['2015.01.01 22:00:10', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:06:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:12', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:07:00', '1.21041', '1.21041', '1.21041', '1.21041'], ['2015.01.01 22:00:14', '1.21038', '1.21038', '1.21038', '1.21038']), (['2015.01.01 22:08:00', '1.21037', '1.21037', '1.21037', '1.21037'], ['2015.01.01 22:00:16', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo', ['2015.01.01 22:00:18', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo', ['2015.01.01 22:00:20', '1.21038', '1.21038', '1.21038', '1.21038']), ('foo',...
Schließlich dachte ich, ich könnte alle 1-Minuten-Daten in ein Wörterbuch einfügen und dann die 17 Zeichen ganz links des 2s-Zeitstempels (z. B. "2015.01.01 22:00:") im Wörterbuch nachschlagen die Verbindung, aber das scheint etwas umständlich (?).
Ich habe auch eine Halbierungsmethode in Betracht gezogen (d. H. Die Minutendaten jedes Mal zu halbieren, wenn ich in den 2s-Datenzeitstempeln ein ": 00" erreiche, aber ich bin nicht sicher, ob dies auch der schnellste Weg ist.
Was wäre der schnellste (oder eleganteste) Weg, um das zu tun, was ich versuche, oder muss ich eine vollständige Schleife schreiben, um die Listen zusammenzufügen?
Jede Hilfe wäre sehr dankbar!
Mit freundlichen Grüßen,
Paul
4 Antworten
Ich würde eine Position in den Minuten-Daten behalten (beginnend mit 0), während ich die zweiten Daten durchlaufe. Jedes Mal, wenn ich in den zweiten Daten ein Minuteninkrement sehe, würde ich diese Position in den Minuten-Daten erhöhen. Dann würde ich die Elemente wie gewünscht yield
:
shortdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
# ...
["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
# ...
]
longdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
# ...
]
def each_mixed_line(sh, lo):
lo_pos = 0
for sh_line in sh:
while lo_pos < len(lo)-1 and lo[lo_pos+1][0] <= sh_line[0]:
lo_pos += 1
yield lo[lo_pos] + [ '', '' ] + sh_line
for mixed_line in each_mixed_line(shortdata, longdata):
print(mixed_line)
In vielen Fällen müssen Sie nicht die vollständige resultierende Liste erstellen, sondern können sie wie mit print()
gezeigt durchlaufen. Dies ist viel weniger speicherintensiv und daher zu empfehlen. Wenn Sie die resultierende Liste erstellen müssen, können Sie dies einfach tun:
combineddata = list(each_mixed_line(shortdata, longdata))
Wenn die Effizienz kein Problem darstellt, können Sie eine verschachtelte for
- Schleife verwenden. Beachten Sie, dass dies eine O (n ^ 2) -Lösung ist.
Der Vorteil ist, dass die Logik enger an den Daten ausgerichtet ist: Sie verwenden datetime
Objekte und prüfen explizit, ob das long_date <= short_date from datetime import datetime, timedelta
d = defaultdict(list)
td = timedelta(0, 60)
res = []
for short in shortdata:
s_date = datetime.strptime(short[0], '%Y.%m.%d %H:%M:%S')
for long in longdata:
l_date = datetime.strptime(long[0], '%Y.%m.%d %H:%M:%S')
if l_date <= s_date < l_date + td:
res.append(long + short)
Wenn es Ihnen nichts ausmacht, Ihre Variable longdata
zu ändern, können Sie einfach jedes Element um die entsprechenden Elemente von shortdata
erweitern. Dies ist effizienter, da nur ein Minimum an neuen Daten zugewiesen wird. Hier ist der Code:
shortdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:00:02","1.21034","1.21039","1.21038","1.21037"],
# ...
["2015.01.01 22:00:58","1.21041","1.21042","1.21047","1.21050"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
["2015.01.01 22:01:02","1.21047","1.21033","1.21035","1.21035"],
# ...
]
longdata = [
["2015.01.01 22:00:00","1.21036","1.21032","1.21033","1.21038"],
["2015.01.01 22:01:00","1.21044","1.21032","1.21033","1.21035"],
# ...
]
n = 0
end = len(shortdata)
for long in longdata:
prefix = long[0][:16] # keep only significant part
long.clear() # because the first line of 'short' is same as 'long'
while n < end:
short = shortdata[n]
if short[0][:16] != prefix: break
long.extend(short + ['/'])
n += 1
print(longdata)
Ergebnis:
[['2015.01.01 22:00:00', '1.21036', '1.21032', '1.21033', '1.21038', '/',
'2015.01.01 22:00:02', '1.21034', '1.21039', '1.21038', '1.21037', '/',
...
'2015.01.01 22:00:58', '1.21041', '1.21042', '1.21047', '1.21050', '/'],
['2015.01.01 22:01:00', '1.21044', '1.21032', '1.21033', '1.21035', '/',
'2015.01.01 22:01:02', '1.21047', '1.21033', '1.21035', '1.21035', '/',
...
'2015.01.01 22:01:58', '1.21041', '1.21042', '1.21047', '1.21050', '/'],
...
]
Sie können auch das innere while
durch einen Iterator auf shortdata
ersetzen, aber ich bin nicht sicher, ob es den Code wirklich beschleunigt. Müssen es zeitlich festlegen ...
Wenn Ihre kurze und lange Liste eine n times longer
Beziehung haben (die n
wäre in Ihrem Beispiel 30)
D.h. longtdata: [[1],[2]], shortdata: [[1.1],[1.2]...[1.n],[2.1],[2.2],...,[2.n],[3.1]...]
Dann können Sie die kurzen Daten durch ausgeben
expended_data = (x for l in longtdata for x in [l]*n)
Oder
expended_data = (x for l in longtdata for i in range(n))
Und das combineddata
wird
combineddata = [a+["",""]+b for a,b in zip(expended_data,shortdata)]
Verwandte Fragen
Neue Fragen
python
Python ist eine dynamisch typisierte Mehrzweck-Programmiersprache mit mehreren Paradigmen. Es wurde entwickelt, um schnell zu lernen, zu verstehen, zu verwenden und eine saubere und einheitliche Syntax durchzusetzen. Bitte beachten Sie, dass Python 2 ab dem 01.01.2020 offiziell nicht mehr unterstützt wird. Fügen Sie für versionenspezifische Python-Fragen das Tag [python-2.7] oder [python-3.x] hinzu. Wenn Sie eine Python-Variante (z. B. Jython, PyPy) oder eine Bibliothek (z. B. Pandas und NumPy) verwenden, fügen Sie diese bitte in die Tags ein.