2016-07-20 8 views
3

Ich versuche eine rekursive Python-Funktion zu erstellen, die eine Liste von Punkten akzeptiert und sie in einer sauberen Zeitleiste konsolidiert. Es sollte durch eine Liste scannen und diese Regeln gelten:Rekursive Listenfunktionen

  • Wenn der Wert von Keine innerhalb der Periode gefunden wird: ersetzen Keine mit datetime.date.today()

  • Wenn eine Periode beginnt innerhalb und endet innerhalb ein anderer Zeitraum: löschen Sie es.

  • Wenn eine Periode beginnt vor aber Enden innerhalb eine andere Zeit: Startdatum verlängern.

  • Wenn eine Periode endet nach aber innerhalb eine weitere Frist beginnt: Enddatum verlängern.

  • Wenn ein Zeitraum beginnt nach und nach endet eine weitere Periode: es halten, es ist eine separate Zeit.

  • Wenn ein Zeitraum beginnt vor und vor endet eine andere Zeit: es halten, dann ist es eine separate Zeit.

Es ist vielleicht viel einfacher zu geben, die ein Beispiel einer Eingangs- und gewünschten Ausgang (sind Werte annehmen, mit Datetime-Format):

[I] = [(01/2011, 02/2015), (04/2012, 08/2014), (09/2014, 03/2015), (05/2015, 06/2016)] 
[O] = [(01/2011, 03/2015), (05/2015, 06/2016)] 
# Notice how the output has produced a set of minimum length whilst covering all periods. 

[I] = [(07/2011, 02/2015), (04/2012, 08/2014), (09/2014, 04/2015), (06/2015, None)] 
[O] = [(07/2011, 04/2015), (06/2015, date.today())] 
# Also, notice how the output has amended None, so it can compare dates. 

Dank @khredos, ich habe geschrieben die folgend, aber es funktioniert immer noch nicht ausgegeben die minimale Zeichenfolge erforderlich:

from datetime import datetime 

# Here is an example list of time periods 
periods = [('01/2011', '02/2015'), ('04/2012', '08/2014'), ('09/2014', '03/2015'), ('05/2015', '06/2016')] 

# this lambda function converts a string of the format you have specified to a 
# datetime object. If the string is None or empty, it uses today's date 
cvt = lambda ds: datetime.strptime(ds, '%m/%Y') if ds else datetime.today() 

# Now convert your original list to an iterator that contains datetime objects 
periods = list(map(lambda s_e : (cvt(s_e[0]), cvt(s_e[1])), periods)) 

# Next get the start dates into one list and the end dates into another 
starts, ends = zip(*periods) 

# Finally get the timeline by sorting the two lists 
timeline = sorted(starts + ends) 

# Output: [datetime.datetime(2011, 1, 1, 0, 0), datetime.datetime(2012, 4, 1, 0, 0), datetime.datetime(2014, 8, 1, 0, 0), datetime.datetime(2014, 9, 1, 0, 0), datetime.datetime(2015, 2, 1, 0, 0), datetime.datetime(2015, 3, 1, 0, 0), datetime.datetime(2015, 5, 1, 0, 0), datetime.datetime(2016, 6, 1, 0, 0)] 
+0

Bitte beachten Sie auch nach, was „Fehler“ Sie über –

+0

Danke für das Feedback kommen. Bitte finden Sie Fehler, die am Ende der Frage hinzugefügt wurden. Ich bekomme Fehler, weil ich versuche, die Hälfte eines Paares zu manipulieren. – alpacinohead

+0

Tupel sind unveränderlich: Sie können den Wert nicht ändern. Wenn Sie es ändern möchten, erstellen Sie entweder ein neues Tupel oder verwenden Sie eine Liste. – Prune

Antwort

2
from datetime import datetime 

# Here is an example list of time periods 
periods = [('01/2011', '02/2015'), ('04/2012', '08/2014'), ('09/2014', '03/2015'), ('05/2015', '06/2016')] 

# this lambda function converts a string of the format you have specified to a 
# datetime object. If the string is None or empty, it uses today's date 
cvt = lambda ds: datetime.strptime(ds, '%m/%Y') if ds else datetime.today() 

Die verfügbaren Formate sind here

# Now convert your original list to an iterator that contains datetime objects 
periods = list(map(lambda s_e : (cvt(s_e[0]), cvt(s_e[1])), periods)) 

# Next get the start dates into one list and the end dates into another 
starts, ends = zip(*periods) 

# Finally get the timeline by sorting the two lists 
timeline = sorted(starts + ends) 

Die Ausgabe sollte mit einer Liste von Daten, die Sie haben, und Sie sollten das gleiche Verhalten es zu

[datetime.datetime(2011, 1, 1, 0, 0), datetime.datetime(2012, 4, 1, 0, 0), datetime.datetime(2014, 8, 1, 0, 0), datetime.datetime(2014, 9, 1, 0, 0), datetime.datetime(2015, 2, 1, 0, 0), datetime.datetime(2015, 3, 1, 0, 0), datetime.datetime(2015, 5, 1, 0, 0), datetime.datetime(2016, 6, 1, 0, 0)] 

Versuchen ähnlich sein beobachten.

HTH

+0

Das ist fantastisch!Vielen Dank für Ihre schnelle Antwort und den Code kurz und bündig zu halten. Ich bekomme Fehler, weil ich Tupel in Python 3 nicht entpacken kann. Diese Zeile fällt um: "Punkte = Karte (Lambda (s, e): (cvt (s), cvt (e)), Punkte)" . Auch die Ausgabe ist keine Liste, also weiß ich nicht, welche Daten gruppiert sind. Könnten Sie möglicherweise Ihre Antwort aktualisieren, um eine Liste mit Start- und Enddaten wie in der Eingabeliste auszugeben? – alpacinohead

+0

@AaronAvocado, aktualisiert gerade die Antwort zur Verwendung der Python 3-Syntax. Leider sieht es so aus, als ob Python 3 das Tupel-Parameter-Entpacken nicht unterstützt, weshalb der Fehler aufgetreten ist. Außerdem gibt die map-Klasse einen Iterator zurück, weshalb die Ausgabe keine Liste war. Alles behoben mit dieser Bearbeitung – smac89

+0

Ausgezeichnet, danke für das Update @Khredos. Das einzige Problem ist, dass das Ausgabearray keine "saubere" Zeitleiste erstellt hat. Die Daten ('04/2015 ', '08/2014') sollten nicht in der Ausgabe erscheinen, da sie in den Zeitraum fallen ('01/2011 ', '02/2015'). Das Ziel des Codes besteht darin, Zeiträume zu entfernen, die innerhalb eines anderen beginnen und enden. verlängern Sie Zeiträume, die innerhalb beginnen, aber außerhalb enden ODER innerhalb beginnen und außerhalb beginnen; Perioden, die außerhalb eines anderen beginnen und enden, sollten als separate Gruppe angezeigt werden. – alpacinohead