Seite 1 von 2

nach Datum sortieren und jüngstes zurückgeben

Verfasst: Donnerstag 22. Mai 2008, 19:50
von mazman
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!

Verfasst: Donnerstag 22. Mai 2008, 20:12
von CM
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 ...

Verfasst: Donnerstag 22. Mai 2008, 20:14
von HWK
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

Verfasst: Donnerstag 22. Mai 2008, 20:18
von numerix
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]

Verfasst: Donnerstag 22. Mai 2008, 20:21
von gerold
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
:-)

Verfasst: Donnerstag 22. Mai 2008, 20:33
von HWK
@pütone: Etwas abgewandelt

Code: Alles auswählen

mindate = '.'.join(min(item[1].split('.')[::-1] for item in a)[::-1])
MfG
HWK

Verfasst: Donnerstag 22. Mai 2008, 20:35
von mazman
vielen dank für die schnelle hilfe !!! :-)

Verfasst: Donnerstag 22. Mai 2008, 20:51
von numerix
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 ...

Verfasst: Donnerstag 22. Mai 2008, 23:50
von EyDu
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)

Verfasst: Freitag 23. Mai 2008, 12:02
von mazman
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!

Verfasst: Freitag 23. Mai 2008, 16:49
von Y0Gi
`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.

Verfasst: Freitag 30. Mai 2008, 13:50
von mazman
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... :)

Verfasst: Freitag 30. Mai 2008, 15:32
von 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

Verfasst: Freitag 30. Mai 2008, 15:59
von audax
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 :]

Verfasst: Freitag 30. Mai 2008, 16:13
von mazman
@ audax:

TypeError: itemgetter expected 1 arguments, got 2

in Zeile: key = itemgetter(1,0)

?

Verfasst: Freitag 30. Mai 2008, 16:18
von audax
Braucht Python2.5, sry :D

Man könnte auch den itemgetter durch lambdas ersetzen...oder updaten. ;)

Verfasst: Freitag 30. Mai 2008, 16:22
von mazman
hmm. es muss irgendwie mit 2.4 gehen...

Verfasst: Freitag 30. Mai 2008, 16:25
von audax
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())

Verfasst: Freitag 30. Mai 2008, 16:26
von mazman
danke!!!

werde mich mal mit dem lamda vertraut machen... :-)

Verfasst: Freitag 30. Mai 2008, 16:28
von audax
Och..brauch man eigentlich eher selten.
Das meiste ist im Modul operator enthalten :]