Datei(Namen) nach Datum sortieren...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

Montag 24. November 2003, 16:12

Hi "Pythons",

irgendwie stehe ich auf´m Schlauch...

Ich habe die Dateinamen in einem Verzeichnis per glob in eine Liste eingelesen - leider haut die Sortierung nicht hin:
nn_1.230.tif
nn_10.349.tif
nn_4.498.tif

sollte eigentlich
nn_1.230.tif
nn_4.498.tif
nn_10.349.tif

lauten - hmmm... dachte, ich nehme einfach das Erstellungstatum und lese/sortiere danach.

Leider habe ich nix gefunden - wie würde man das bei einem Dateiviewer machen, um nach Datum zu sortieren ??
gruss x-herbert
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Montag 24. November 2003, 16:50

Hi x-herbert,

das erste ist asciimässig richtig sortiert. Du kannst bei der Methode sort von Listen auch eine eigene cmp-Funktion angeben, nach der dann sortiert wird.


Gruß

Dookie
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Montag 24. November 2003, 17:02

ich hab mal für Deinen speziellen fall was zusammengewurschtelt:

Code: Alles auswählen

dateiliste.sort(lambda x,y: cmp(map(int,x[3:-4].split(".")),  map(int,y[3:-4].split("."))))
Gruß

Dookie
joerg
User
Beiträge: 188
Registriert: Samstag 17. August 2002, 17:48
Wohnort: Berlin
Kontaktdaten:

Montag 24. November 2003, 17:03

x-herbert hat geschrieben:Leider habe ich nix gefunden - wie würde man das bei einem Dateiviewer machen, um nach Datum zu sortieren ??
Bei den Dateinamen müßtest Du erst Zahlen im String finden und die vergleichen, der reiner Stringvergleich bringt hier nicht das von dir gewünschte.

Zu den Erstellungszeiten:

Prinzipiell kannst Du der Methode sort() einer Liste auch eine Vergleichsfunktion mitgeben, die kann dann z.B. os.path.getmtime() benutzen.

Um zu vermeiden, daß diese Funktion aber sehr oft gerufen wird, kann man es auch alternativ so machen:

>>> import glob, os
>>> files = glob.glob("*")
>>> tmp = [(os.path.getmtime(f), f) for f in files]
>>> tmp.sort()
>>> files = [f for t,f in tmp]

Genauso könntest Du auch nach Dateigröße etc. sortieren.

Jetzt hagelt es bestimmt Optimierungsvorschläge.... duck!

Jörg
"Sie sind nicht berechtigt, unrechtmäßige Kopien dieses Datenträgers zu erstellen." - Microsoft-Weisheit auf einer CD von MS-VisualC++-6.0
Benutzeravatar
strogon14
User
Beiträge: 58
Registriert: Sonntag 23. Februar 2003, 19:34
Wohnort: Köln
Kontaktdaten:

Montag 24. November 2003, 23:46

joerg hat geschrieben: Jetzt hagelt es bestimmt Optimierungsvorschläge.... duck!
Nö, wieso. Deine Lösung ist das typische Decorate/Sort/Undecorate Pattern!

Geht nun mal nicht schneller (und einfacher schon mal gar nicht ;-).

Chris
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

Dienstag 25. November 2003, 09:42

Hi,

danke für die Hinweise....

Bezüglich der Sortierung von Datei(Namen) nach verschiedenen Eigenschaften hatte ich ein kleines Script find.py gefunden - darin wurde nach Erstellungsdatum wie folgt sortiert:

filelist= map( lambda f: (os.stat(f)[ST_MTIME], f), filelist )
gruss x-herbert
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

Dienstag 25. November 2003, 09:49

NACHTRAG:

kommt natürlich noch´n filelist.sort() dazu...

Ich bin erstaunt, dass solche "natürlichen" Sortierungen noch nicht enthalten sind, wie ich sie z.B. von PHP kenne (natsort()). Für 2.3.x habe ich diesbezüglich bei sourceforge was gefunden [url]http://py-stablesort.sourceforge.net/[/url]
gruss x-herbert
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Dienstag 25. November 2003, 11:14

Hallo!
x-herbert hat geschrieben:Ich bin erstaunt, dass solche "natürlichen" Sortierungen noch nicht enthalten sind, wie ich sie z.B. von PHP kenne (natsort()).
Was man so 'natürlich' nennt ;-). Ist ein nettes Feature, für das man bei PHP sicherlich häufiger Verwendung hat. PHP hat ja einige *nat*-Funktionen. Die in Python würd' ich nicht haben wollen. Das wird dann doch arg überfrachtet.
x-herbert hat geschrieben:Für 2.3.x habe ich diesbezüglich bei sourceforge was gefunden http://py-stablesort.sourceforge.net/
Soweit ich das sehe, geht es da nur um das sog. stabile Sortieren. Die sort()-Funktion älterer Python-Vesionen sortiert nämlich nicht stabil, die derzeitige Version tut es; aber bei zukünftigen Versionen kann das schon wieder anders ausehen, denn das stabile Sortieren ist keine garantierte Eigenschaft von sort().

Jan
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

Dienstag 25. November 2003, 15:53

Hi,

über eine Lambda-Routine ist sicher einer der besseren Wege
z.B.

Code: Alles auswählen

dateiliste = ['nn_1.230.tif','nn_1.0543.tif','nn_12.2543.tif','nn_4.498.tif','nn_10.349.tif','askfj_aaf_a123_0.349.tif']

dateiliste.sort(lambda x,y: cmp(float(x.split("_")[-1].replace(".tif","")),float(y.split("_")[-1].replace(".tif",""))))

print dateiliste
ergibt
['askfj_aaf_a123_0.349.tif', 'nn_1.0543.tif', 'nn_1.230.tif', 'nn_4.498.tif', 'nn_10.349.tif', 'nn_12.2543.tif']

die Dateinamen haben die allgemeine Form
"irgendwas_zahl.tif" wobei Dezimaltrenner der Zahl ein Punkt ist

was ich bei Dookie nicht durchschaue, warum die map-Funktion eingefügt wurde??
gruss x-herbert
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Dienstag 25. November 2003, 16:13

Hallo!
x-herbert hat geschrieben:

Code: Alles auswählen

dateiliste.sort(lambda x,y: cmp(float(x.split("_")[-1].replace(".tif","")),float(y.split("_")[-1].replace(".tif",""))))
Man sollte allerdings bedenken, dass die lambda-Funktion u.U. ziemlich häufig aufgerufen wird. 10x erfolgt bei Deinem Beispiel der Aufruf, also 20x split(), replace() und Konvertierung nach float.
Bei einer Handvoll Dateien sicherlich kein Problem. Ansonsten ist joergs Weg über die Tupel-Liste sicherlich performanter. Und dass das auch noch "Decorate/Sort/Undecorate Pattern" heißt, muss ich mir unbedingt merken ;-)

Jan
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Dienstag 25. November 2003, 18:58

mit dem map mache ich aus den Zahlenstrings Integerwerte, die sich dann natürlich sortieren lassen.
Falls die Möglichkeit besteht, die Dateien vor dem verarbeiten umzubenennen, würde ich sie gleich mit Dateinamen in der Form "YYYY-MM-DD-hh-mm-ss.tif" dbei steht YYYY für das Jahr, MM für den Monat u.s.w.. Speichern so können sie einfach nach Datum/Uhrzeit sortiert werden.

Gruß

Dookie
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Dienstag 25. November 2003, 21:05

Voges hat geschrieben:Soweit ich das sehe, geht es da nur um das sog. stabile Sortieren. Die sort()-Funktion älterer Python-Vesionen sortiert nämlich nicht stabil, die derzeitige Version tut es; aber bei zukünftigen Versionen kann das schon wieder anders ausehen, denn das stabile Sortieren ist keine garantierte Eigenschaft von sort().
Was macht denn den Unterschied? Dort stand, dass es um Geschwindigkeit und Arbeitsspeicher geht, aber wonach entscheidet sich, welche Variante gefahren wird?
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Dienstag 25. November 2003, 23:09

Hallo Milan!
Milan hat geschrieben:Was macht denn den Unterschied? Dort stand, dass es um Geschwindigkeit und Arbeitsspeicher geht, aber wonach entscheidet sich, welche Variante gefahren wird?
Beim 'stabilen' Sortieren ist sichergestellt, dass gleiche Elemente nicht getauscht werden. Beispiel: Sortieren nach Namen. Zuerst sortiert man nach Vornamen und dann mit einem zweiten sort()-Aufruf nach Nachnamen. Wurde 'stabil' sortiert, ist die Reihenfolge der Vornamen innerhalb der Müllers und Lehmanns unverändert, was ja wünschenswert ist. Das ist natürlich ein Zusatz-Feature, das es nicht umsonst gibt.

Zum Thema Sortieren gibt das Cookbook[1] ja auch Einiges her.
Zudem fand ich eben Folgendes:
http://www.python.org/dev/summary/2003- ... t-sort-guy

Jan

[1] http://aspn.activestate.com/ASPN/Cookbo ... =Searching
x-herbert
User
Beiträge: 59
Registriert: Mittwoch 27. November 2002, 20:52

Donnerstag 27. November 2003, 12:48

Also....

"back to the roots":

Ich arbeite mit einem Simulationsprogramm (CFD) welches mir zu jedem Zeitschritt ein Hardcopy meines Strömungszustandes ausgibt/abspeichert.

Der Dateiname ist so angelegt, dass ich einen allemeinenen Dateinamen vergeben kann, an dem mit einem Underline getrennt der Zeitschritt angehängt wird + ein Punkt + Extension.

Da das Programm mit englischer Notation arbeitet, sind die Zahlen der Zeitschritte mit einem Punkt getrennt.

Also:
meindateiname_0.0.tif
meindateiname_0.001.tif
meindateiname_0.002.tif
meindateiname_0.003.tif
meindateiname_0.045.tif

Die Zeitabstände sind nicht immer äquidistant.


Die Sortierung nach dem Erstellungsdatum war nur ein Workaround, da ich die andere Sortierung auf anhieb nicht hinbekommen habe.

Daher ist die Lösung nicht das, was ich eigentlich suchte.

Die Frage steht daher, ob es "elegantere" bzw. performantere Alternativen zu meinem letzten "Lambda" gibt.

Die Datenmenge liegt etwa zwischen 1000 und 6000 Dateien - mit der Liste werden anschließend die einzelnen Dateien "angefasst" und zu einem AVI "verbastelt".

Danke nochmal für die Tipps!
gruss x-herbert
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Donnerstag 27. November 2003, 14:15

Hallo!
x-herbert hat geschrieben:"back to the roots"!
Ich gehe mal davon aus, dass der allg. Teil des Dateinamens immer gleich und bekannt ist (für letztes muss man ja vorab nur eine der Dateien auswerten). Dann ist nämlich schonmal die Anfangsposition des Zeitwertes klar, die Endposition sowieso.

Code: Alles auswählen

iStart = len("meindateiname_")
dateien = ["meindateiname_0.0.tif","meindateiname_0.001.tif"]
liste = [(float(datei[iStart:-4]),datei) for datei in dateien]
liste.sort()
liste = [b for a,b in liste]
Also im Prinzip genau das, was bereits im bisherigen Thread schon erwähnt und verwendet wurde. Ob man da noch was optimieren kann? Zur not müsste man ein Modul auf C-Basis schreiben, das scanf bzw. sscanf verwendet (wird es sicherlich schon irgenwo geben).

Jan
Antworten