Elemente einer aus Listen bestehende Liste neu 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.
Antworten
Rotkehlchen
User
Beiträge: 20
Registriert: Freitag 7. Dezember 2018, 07:39

Hallo liebes Forum,
Ihr habt mir schon oft weitergeholfen und ich hoffe, dass das auch diesmal der Fall sein wird :)
Ich habe folgendes vor:
Aus ein paar Excel-Tabellen habe ich Daten ausgelesen und je eine Tabellenzeile als Liste in einer (zusammenfassenden) Liste gespeichert. Das sieht ungefähr so aus:

Code: Alles auswählen

data = [['Gruppe1', 'bewertet', 'kein Kommentar'], ['Gruppe4', 'nicht bewertet', 'kein Kommentar'], ...] 
Hierbei kommen manche Gruppen mehrfach vor, andere nicht. Mein Ziel ist es nun, die Ergebnisse jeder Gruppe zusammenzufassen, also z. B. so:

Code: Alles auswählen

summary = [['Gruppe1', '3 mal bewertet, 1 mal nicht bewertet', '4 mal kein Kommentar'], ['Gruppe2', '2 mal bewertet', 'Kommentar: Bewertung noch nicht abgeschlossen'], ...]
Insbesondere sollen also keine Dopplungen des jeweils ersten Listenelements (Gruppennummer) mehr auftreten, und die Anzahl der Bewertungen gleichnamiger Gruppen soll angegeben werden. Ist es überhaupt möglich, eine Liste so zusammenzufassen?

Vielen Dank für jede Hilfe!
Rotkehlchen
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dazu gibt es die Funktion "itertools.groupby"

Code: Alles auswählen

from itertools import groupby

data = [
    ['Gruppe1', 'bewertet', 'kein Kommentar'],
    ['Gruppe4', 'nicht bewertet', 'kein Kommentar'],
    ['Gruppe1', 'nicht bewertet', 'alle doof ausser Mutti!'],
]


keyfunc = lambda entry: entry[0]

for key, entries in groupby(sorted(data, key=keyfunc), keyfunc):
    print(key)
    for entry in entries:
        print(entry)
Innerhalb der Eintraege kannst du dann wiederum mit anderen Mitteln aggregieren, wie zB collections.Counter fuer die Anzahl von Bewertung/nicht Bewertung etc.
Benutzeravatar
__blackjack__
User
Beiträge: 13072
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Rotkehlchen: Das sieht mir nach einem Fall für ein `collections.defaultdict()` das Gruppennamen auf `collections.Counter`-Objekte abbildet, die Du entsprechend `update()`test.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Rotkehlchen
User
Beiträge: 20
Registriert: Freitag 7. Dezember 2018, 07:39

Danke für die schnellen Antworten!
Da ich die von __deets__ zuerst gesehen habe, habe ich damit einen (vorläufigen) Versuch gewagt:

Code: Alles auswählen

def sort_data(data):
  temp_summary = []
  summary = []
  keyfunc = lambda entry: entry[0]
  for key, entries in groupby(sorted(data, key = keyfunc),keyfunc):
    temp = [key]
    for entry in entries:
      temp.append(entry[1])
    temp_summary.append(temp)
  for listelement in temp_summary:
    a = str(listelement.count("bewertet")) + " mal bewertet"
    b = str(listelement.count("nicht bewertet")) + " mal nicht bewertet"
    summary.append([listelement[0], a, b])
  return summary
(Hierbei habe ich die Kommentarelemente mal weggelassen, ist ja mehr oder weniger das gleiche Prinzip wie bei den Bewertungen.)
Als Ergebnis bekomme ich z. B.:

Code: Alles auswählen

>>> summary[4]
['Gruppe5', '2 mal bewertet', '1 mal nicht bewertet']
Damit bin ich an sich schon zufrieden, aber der Code könnte wohl auch eleganter sein... danke jedenfalls für die Hilfe, vielleicht hat jemand noch einen Tipp :)
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird in Python immer mit 4 Leerzeichen pro Ebene, nicht 2.
Eine Liste, deren erstes Element etwas anderes bedeutet, als die restlichen, ist schlecht. Nimm statt dessen z.B. ein Tuple mit key und entry-Liste.
Warum heißen die Variablen temp und temp_summary? Bisher hatte ich nicht gesehen, dass es sich um Temperaturen handelt.
String stückelt man nicht mit + zusammen, sondern benutzt Stringformatierung. Hier würde man aber gar keine fertig formatierten Strings zurückliefern, sondern die Zahlenwerte, mit denen kann man besser weiterarbeiten. Erst bei der Ausgabe schön lesbare Strings umwandeln.
Rotkehlchen
User
Beiträge: 20
Registriert: Freitag 7. Dezember 2018, 07:39

Hallo Sirius3,
war meine Voreinstellung in IDLE, darüber habe ich mir noch nie Gedanken gemacht...
Aber wie erstelle ich diese Tupel, schließlich kann ich da ja nichts mehr hinzufügen, so wie ich das letzte Woche mit meiner for-Schleife gemacht habe?
Mit temp meinte ich temporär, da ich diese Listen am Schluss nicht ausgeben lasse.
Okay, das mit den Strings habe ich auch erst mal nur zu meiner Kontrolle gemacht, ob das am Schluss alles so angeordnet ist, wie ich es brauche.
Danke für Deine Antwort!
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Rotkehlchen: jede lokale Variable ist temporär. Das in den Namen zu schreiben, ist also unsinnig.
Du brauchst auch das Tuple nicht nachträglich zu ändern, weil Du es erst zum Schluß erzeugst, also erst eine entries-Liste, und dann diese zusammen mit dem key in ein Tuple:

Code: Alles auswählen

def sort_data(data):
    keyfunc = lambda entry: entry[0]
    groups = []
    for key, entries in groupby(sorted(data, key=keyfunc),keyfunc):
       evaluations = []
       for entry in entries:
           evaluations.append(entry[1])
       groups.append((key, evaluations))
    summary = []
    for key, evaluations in groups:
        a = evaluations.count("bewertet")
        b = evaluations.count("nicht bewertet")
        summary.append((key, a, b))
    return summary
das ganze könnte man auch noch in eine Schleife zusammenfassen:

Code: Alles auswählen

def sort_data(data):
    keyfunc = lambda entry: entry[0]
    summary = []
    for key, entries in groupby(sorted(data, key=keyfunc), keyfunc):
        evaluations = [entry[1] for entry in entries]
        a = evaluations.count("bewertet")
        b = evaluations.count("nicht bewertet")
        summary.append((key, a, b))
    return summary
oder statt groupby mit defaultdict:

Code: Alles auswählen

def sort_data(data):
    groups = defaultdict(list)
    for entry in data:
        groups[entry[0]].append(entry[1])
    summary = []
    for key, evaluations in groups.items():
        a = evaluations.count("bewertet")
        b = evaluations.count("nicht bewertet")
        summary.append((key, a, b))
    return summary
Rotkehlchen
User
Beiträge: 20
Registriert: Freitag 7. Dezember 2018, 07:39

Wow, Sirius3, jetzt habe ich echt die Qual der Wahl!
Danke für die schnelle Antwort, das hat mir sehr weitergeholfen!
Und ja, ich bin nicht so kreativ mit den Variablennamen...
Antworten