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

1
Paul 17 Apr. 2018 im 16:55

4 Antworten

Beste Antwort

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))
1
Alfe 17 Apr. 2018 im 14:17

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)
0
jpp 19 Apr. 2018 im 08:39

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 ...

0
sciroccorics 17 Apr. 2018 im 16:01

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)]
1
apple apple 19 Apr. 2018 im 13:34