Seite 1 von 1
Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:02
von api
Hallo,
ich habe eine Liste, die wie folgt aussieht:
liste =['SNAP_20120105_101306.bz2', 'mod.prot_SNAP_20120106_101306.bz2', 'mod.prot42.SNAP_20100109_101311.bz2', 'SNAP_20100305_103306.bz2', 'mod.prot_SNAP_20110705_121301.bz2', 'folio_20100112_102206.bz2', 'SNAP_20100112_102206.bz2', 'mod.prot42.SNAP_20120134_101809.bz2', 'SNAP_20120912_101306.bz2', 'mod.prot_SNAP_20120312_091306.bz2', 'folio_20100109_102206.bz2']
Diese Liste möchte ich nun sortieren/gruppieren, so dass ich dann als Ausgabe folgendes erhalte:
liste_2010 = [['folio_20100109_102206.bz2', 'folio_20100112_102206.bz2'], ['mod.prot42.SNAP_20100109_101311.bz2'], ['SNAP_20100112_102206.bz2', 'SNAP_20100305_103306.bz2']]
Es soll also eine neue Liste generiert werden, die alle Daten aus dem Jahr 2010 enthält, gruppiert nach dem String, der sich vor der Jahreszahl befindet.
Wie stelle ich das am geschicktesten an?
Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:25
von Hyperion
Ich würde das so angehen:
Code: Alles auswählen
from collections import defaultdict
d = defaultdict(list)
for filename in filenames:
group, year = re.search(r"(.*)_(\d{4})\d{4}_", filename).groups()
if int(year) == 2010:
d[group].append(filename)
print d.values()
Das ist natürlich nocht nicht "optimiert"; man sollte den RegExp kompilieren.
Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:25
von snafu
Ich kopiere einfach mal die Ausgaben aus der IPython-Shell:
Code: Alles auswählen
In [1]: from collections import defaultdict
In [2]: ergebnisse = defaultdict(list)
In [3]: liste =['SNAP_20120105_101306.bz2', 'mod.prot_SNAP_20120106_101306.bz2', 'mod.prot42.SNAP_20100109_101311.bz2', 'SNAP_20100305_103306.bz2', 'mod.prot_SNAP_20110705_121301.bz2', 'folio_20100112_102206.bz2', 'SNAP_20100112_102206.bz2', 'mod.prot42.SNAP_20120134_101809.bz2', 'SNAP_20120912_101306.bz2', 'mod.prot_SNAP_20120312_091306.bz2', 'folio_20100109_102206.bz2']
In [4]: for element in liste:
...: name, datum = element.split('_', 1)
...: if datum.startswith('2010'):
...: ergebnisse[name].append(element)
...:
...:
In [5]: ergebnisse
Out[5]: defaultdict(<type 'list'>, {'SNAP': ['SNAP_20100305_103306.bz2', 'SNAP_20100112_102206.bz2'], 'folio': ['folio_20100112_102206.bz2', 'folio_20100109_102206.bz2'], 'mod.prot42.SNAP': ['mod.prot42.SNAP_20100109_101311.bz2']})
In [6]: ergebnisse.values()
Out[6]:
[['SNAP_20100305_103306.bz2', 'SNAP_20100112_102206.bz2'],
['folio_20100112_102206.bz2', 'folio_20100109_102206.bz2'],
['mod.prot42.SNAP_20100109_101311.bz2']]
Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:29
von snafu
Hyperion hat geschrieben:Das ist natürlich nocht nicht "optimiert"; man sollte den RegExp kompilieren.
Braucht man nicht. Eine gewisse Anzahl an zuletzt kompilierten regulären Ausdrücken wird automatisch gecached (s. Modulquelltext).
Im übrigens fehlt bei uns beiden noch das `sorted(d.values())`.

Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:30
von Hyperion
@snafu: Auf `split` wollte ich auch erst setzen; aber dann fiel mir u.a. der zweite Eintrag der Liste auf. Da kommt noch ein "_" vor dem Datum... somit funzt Deine Lösung hier "zufällig". Robuster ist es hier über RegExps zum Ziel zu gelangen.
Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 12:33
von snafu
Hyperion hat geschrieben:@snafu: Auf `split` wollte ich auch erst setzen; aber dann fiel mir u.a. der zweite Eintrag der Liste auf. Da kommt noch ein "_" vor dem Datum... somit funzt Deine Lösung hier "zufällig". Robuster ist es hier über RegExps zum Ziel zu gelangen.
Hast auf jeden Fall recht. So gründlich hatte ich mir das Schema der Vorgabe garnicht angeguckt.
Ohne Zweifel bringt es für einen möglichen Verwendungszweck als eine Funktion, die das gewünschte Jahr als Argument nimmt, natürlich auch mehr, das geparste Jahr in eine "echte" Zahl zu wandeln. Meins war eher Quick&Dirty.

Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 14:07
von api
@snafu, Hyperion:
Ja - super !!
Wenn ich mir eure Lösungen so anschaue, dann sieht das so einfach aus.
Tja, was soll ich sagen. Besten Dank!!!

Re: Gruppieren innerhalb einer Liste
Verfasst: Dienstag 27. März 2012, 14:56
von snafu
@Hyperion:
Code: Alles auswählen
re.split('(?<=\D)_(?=\d)', 'mod.prot_SNAP_20120106_101306.bz2')
...scheint ähnlich robust zu sein und ist für jemanden, der ein bißchen Ahnung von regulären Ausdrücken hat (oder notfalls weiß, wo er nachgucken muss), IMHO etwas naheliegender.
Vielleicht kurz für diejenigen, die es nicht auf Anhieb "entziffern" können:
Suche nach "Nicht-Zahl" (also hier: Buchstabe oder Unterstrich), gefolgt von Unterstrich, gefolgt von Zahl. Es wird Gebrauch von Lookbehind (`(?<=...)`) und Lookahead (`(?=...)`) gemacht. Das kleine `\d` matcht alle Ziffern, das große `\D` ist das genaue Gegenteil. Der Unterstrich selbst fungiert als Trennzeichen.
EDIT: Ok, man hätte bei einem festen Datumsformat nicht direkt die Jahreszahl isoliert. Daran hatte ich jetzt nicht gedacht.