nach Datum sortieren und jüngstes zurückgeben

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.
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

Hallo,
ich habe eine Tabelle a mit bestimmten Inhalt. Aus dieser Tabelle möchte ich mittels einer Funktion das jüngste bzw. älteste Datum zurück geben lassen (nachdem bei gleichen Daten die Fläche addiert wurde, was aber nicht entscheidend ist). Nur weiss ich nicht so richtig wie ich das machen soll. Muss ich das Datum erst splitten und dann sortieren oder gibts da schon was in Python?
Bin nicht so super fit darin. Hier mal der Code. Dort wo die ??? sind fällt mir leider nichts gescheites ein.

Code: Alles auswählen

a = [(5224,"12.01.2005"),(5524,"10.01.2003"),(1524,"12.01.2005"),(5524,"14.01.2005"),(524,"12.01.2008")]

def jung(table):
  #Juengstes Datum soll zurueckgegeben werden! 
  result_jung = dict()
  for area, year in table:
    result_jung[year] = result_jung.get(year, 0) + area
    #result_jung --> {'14.01.2005': 5524, '12.01.2005': 6748, '10.01.2003': 5524, '12.01.2008': 524}
  Zeit_jung = result_jung.sort() #hier soll das jüngste Datum ermittelt werden???
  return Zeit_jung
Bin für jeden Vorschlag dankbar!
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

wenn Du das [mod]datetime[/mod]-Modul nutzt geht es auch so:

Code: Alles auswählen

from datetime import date

a = [(5224, date(2005, 01, 12)), (5524, date(2003, 01, 10)),
     (1524, date(2005, 01, 12)), (5524, date(2005, 01, 14)),
     (524, date(2008, 01, 12))]

if __name__ == "__main__":
    print sorted(a, key=lambda x: x[1])
    # und das jüngste Datum:
    print sorted(a, key=lambda x: x[1])[-1]
    # oder
    a.sort(key=lambda x: x[1])
usw.

HTH,
Christian

edit: Zweimal Nonsens rauseditiert ...
Zuletzt geändert von CM am Donnerstag 22. Mai 2008, 20:19, insgesamt 2-mal geändert.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Speichere das Datum als datetime.date. Das kannst Du ganz normal sortieren. Das jüngste Datum wäre z.B. max(result_jung.keys()).
MfG
HWK
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Und wenn du kein extra Modul importieren willst, geht es auch so:

Code: Alles auswählen

a = [(5224,"12.01.2005"),(5524,"10.01.2003"),(1524,"12.01.2005"),(5524,"14.01.2005"),(524,"12.01.2008")]
d = min(["".join(item[1].split(".")[::-1]) for item in a])
mindate = d[6:]+"."+d[4:6]+"."+d[:4]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo!

:-) Ich habe auch noch etwas um zur Verwirrung beizutragen:

Code: Alles auswählen

# verschachtelt
>>> a = [(5224,"12.01.2005"),(5524,"10.01.2003"),(1524,"12.01.2005"),(5524,"14.01.2005"),(524,"12.01.2008")]
>>> a_index = sorted([ (sorted(item[1].split("."), reverse = True), index) for (index, item) in enumerate(a) ])
>>> a_index
[(['2003', '10', '01'], 1), (['2005', '12', '01'], 0), (['2005', '12', '01'], 2), (['2005', '14', '01'], 3), (['2008', '12', '01'], 4)]
>>> a[a_index[0][1]]
(5524, '10.01.2003')
>>> a[a_index[-1][1]]
(524, '12.01.2008')
>>> 

# einzeln
>>> a = [(5224,"12.01.2005"),(5524,"10.01.2003"),(1524,"12.01.2005"),(5524,"14.01.2005"),(524,"12.01.2008")]
>>> a_index = [ (item[1].split("."), index) for (index, item) in enumerate(a) ]
>>> a_index
[(['12', '01', '2005'], 0), (['10', '01', '2003'], 1), (['12', '01', '2005'], 2), (['14', '01', '2005'], 3), (['12', '01', '2008'], 4)]
>>> for item in a_index:
...     item[0].sort(reverse = True)
...     
>>> a_index
[(['2005', '12', '01'], 0), (['2003', '10', '01'], 1), (['2005', '12', '01'], 2), (['2005', '14', '01'], 3), (['2008', '12', '01'], 4)]
>>> a_index.sort()
>>> a[a_index[0][1]]
(5524, '10.01.2003')
>>> a[a_index[-1][1]]
(524, '12.01.2008')
>>>
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@pütone: Etwas abgewandelt

Code: Alles auswählen

mindate = '.'.join(min(item[1].split('.')[::-1] for item in a)[::-1])
MfG
HWK
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

vielen dank für die schnelle hilfe !!! :-)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

HWK hat geschrieben:@pütone: Etwas abgewandelt

Code: Alles auswählen

mindate = '.'.join(min(item[1].split('.')[::-1] for item in a)[::-1])
Ja, das ist schöner.

Ich wollte auch einen eleganten Einzeiler draus machen, hatte aber auf die Schnelle nicht geklappt ...
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich würde es auch so machen wie CM, das ist einfach die sauberste Lösung. Wenn du aus irgend einem Grund die Daten als String speichern musst, kannst du mit dem time-Modul auch einen Zwischenschritt machen:

Code: Alles auswählen

import time
FORMAT = "%d.%m.%Y"
x = min(time.strptime(x, FORMAT) for _,x in a)
print time.strftime(FORMAT, x)
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

Die Daten kommen schon als String. Das kann ich nicht einfach ändern, da es wirklich eine sehr große Liste ist. Aber habe schon eine Lösung umgesetzt und die passt...

PS: Echt ein gutes Forum mit schneller und guter Hilfe!
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

`datetime.date` wäre natürlich am schönsten, da diese Objekte verglichen und dadurch auch mit `min()` und `max()` genutzt werden können. `datetime` ist wirklich ein Modul, auf dessen Import man einfach nicht verzichten darf :)

Du hast Strings, ok. Besonders einfach wäre natürlich, wenn diese in umgekehrter Form vorlägen: "2007-11-23" - dann ließen sie sich ganz einfach sortieren. Hast du vielleicht da Einfluss drauf? Die deutsche Notation ist nämlich für die Datenhaltung denkbar ungeeignet.

Wie liegt diese Liste denn überhaupt vor? Die Strings beim Einlesen in `date`-Objekte umzuwandeln ist ja nun auch kein Performancekiller.
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

Also die Liste (Fläche, Jahr) ist jetzt einfacher geworden, da nur noch das Jahr benötigt wird.

Code: Alles auswählen

a = [(5224,"2005"),(5524,"2003"),(1524,"2005"),(554,"2008"),(5824,"2005"),(524,"2008")]
Das mit dem Split dürfte nun nicht mehr nötig sein. Ich brauche nun aber das jüngste und älteste Datum (Jahr) aus der Liste. Weiterhin sollen Flächen mit dem gleichen Jahr addiert werden. Und die größte Fläche dieser Additionen soll ausgegeben werden sowie welches Jahr es ist. Bei dem jüngsten und ältesten Jahr brauche ich auch die addierte Fläche. Also bei dem jüngsten und ältesten Datum basiert das ganze auf dem Jahr und bei der Flächengeschichte auf der Fläche und dem Jahr. Und die komplette Fläche aller Jahre. Hoffe das hat jetzt jemand verstanden.

Als Ergebnis sollte irgendwie folgendes herauskommen:

jüngstes Jahr = 2003 mit Gesamtfläche 5524
ältestes Jahr = 2008 mit Gesamtfläche 1078
Jahr mit größtem Flächenanteil = 2005 mit Gesamtfläche 12572
Komplettfläche = 19174

Bin für jeden Vorschlag dankbar... :)
BlackJack

Code: Alles auswählen

from collections import defaultdict
from operator import itemgetter

def main():
    data = [(5224, '2005'),
            (5524, '2003'),
            (1524, '2005'),
            (554, '2008'),
            (5824, '2005'),
            (524, '2008')]
    
    year2area = defaultdict(int)
    for area, year in data:
        year2area[year] += area
    
    min_year, max_year = itemgetter(0, -1)(sorted(year2area.iteritems()))
    greatest_area = max(year2area.iteritems(), key=itemgetter(1))
    total_area = sum(year2area.itervalues())
    
    for description, (year, area) in (('juengstes Jahr', min_year),
                                      ('aeltestes Jahr', max_year),
                                      ('Jahr mit groesstem Flaechenanteil',
                                       greatest_area)):
        print '%s = %s mit Gesamtflaeche %d' % (description, year, area)
    print 'Komplettflaeche =', total_area
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Fear the mighty itertools!

Code: Alles auswählen

from itertools import groupby, imap
from operator import itemgetter

a = [(5224,"2005"),(5524,"2003"),(1524,"2005"),(554,"2008"),(5824,"2005"),(524,"2008")]

s = sorted((int(year), area) for area, year in a)

data = {}
for k, g in groupby(s, itemgetter(0)):
    data[k] = sum(imap(itemgetter(1), g))

years = sorted(data.keys())
max_area = sorted(data.iteritems(),
    key=itemgetter(1,0)
    )[-1][0] # max and year

for year, text in [
        (years[0], "earliest %d: %d"),
        (years[-1], "oldest %d: %d"),
        (max_area, "biggest area %d: %d")]:
    print text % (year, data[year])
         
print "full area: %d" % sum(data.itervalues())

€dit:
Bäh. Dazwischenposter!
€dit²:
Gesamtfläche vergessen :]
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

@ audax:

TypeError: itemgetter expected 1 arguments, got 2

in Zeile: key = itemgetter(1,0)

?
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Braucht Python2.5, sry :D

Man könnte auch den itemgetter durch lambdas ersetzen...oder updaten. ;)
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

hmm. es muss irgendwie mit 2.4 gehen...
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Ich sag doch: Nimm halt lambda.

Code: Alles auswählen

from itertools import groupby, imap
from operator import itemgetter

a = [(5224,"2005"),(5524,"2003"),(1524,"2005"),(554,"2008"),(5824,"2005"),(524,"2008")]

s = sorted((int(year), area) for area, year in a)

data = {}
for k, g in groupby(s, itemgetter(0)):
    data[k] = sum(imap(itemgetter(1), g))

years = sorted(data.keys())
max_area = sorted(data.iteritems(),
        key=lambda elem: (elem[1], elem[0])
        )[-1][0] # max and year

for year, text in [
        (years[0], "earliest %d: %d"),
        (years[-1], "oldest %d: %d"),
        (max_area, "biggest area %d: %d")]:
    print text % (year, data[year])
         
print "full area: %d" % sum(data.itervalues())
mazman
User
Beiträge: 22
Registriert: Mittwoch 12. März 2008, 15:39

danke!!!

werde mich mal mit dem lamda vertraut machen... :-)
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Och..brauch man eigentlich eher selten.
Das meiste ist im Modul operator enthalten :]
Antworten