Hi,
Ich habe gerade erst mit Python begonnen (2.7) und habe eine, zumindest für mich recht knifflige Frage.
ich habe ein Dic das so aussieht:
defaultdict(<type 'list'>, {'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514], 'Das Sparschwein im Wandel der Zeiten': [['Konvertierungsanleitung', '60'], ['Sonstiges', '120'], 180], 'Schlager 1': [['Konvertierungsanleitung', '150'], 150], 'RWZ 1': [['Absatzkontrolle', '170'], ['Konvertierungsanleitung', '180'], ['Absatzkontrolle', '60'], 410], 'RWZ 3': [['Absatzkontrolle', '55'], ['Konvertierungsanleitung', '60'], 115]})
Also es gibt zu jedem Key eine Liste die mind. eine weitere Liste enthält und eine Zahl enthält.
Nun kann es auch sein das diese Liste mehrere Listen enthält wie zb gleich beim Ersten Key ("Dumme...").
Diese Listen unterscheiden sich manchmal nur durch die Zahl die an der 2ten Position steht.
Ich würde nun gerne genau solche Listen zusammenfassen, wobei die Zahlen immer Addiert werden.
Um beim 1. Key zu bleiben:
aus
'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514]
sollte dann
'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', 514'], 514]
Ich hoffe ich habe mich verständlich ausgedrückt.
Ich habe versucht die SuFu zu verwenden, aber hab nicht wirklich etwas gefunden. Vlt. hab ichs auch einfach net verstanden weil ich erst seit 1 Monat Python lerne.
Listen zusammenfassen
@patmaster: Es wäre ja fast einfach, wenn da nicht die Zahl am Ende in der Liste wäre. In Listen sollte man möglichst nur "gleichartige" Elemente stecken, damit man diese verarbeiten kann ohne den Typ von Elementen testen zu müssen und dann basierend auf dem Typ etwas bestimmtes zu tun oder es eben zu lassen.
Du musst das Problem auf kleinere Teilprobleme runter brechen. Das grosse Problem was Du uns hier zeigst, ist sicher noch nicht das Minimalproblem wo Du Deine Schwierigkeiten hast. Denn für das Zusammenfassen von ``[['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514]`` zu [['Absatzkontrolle', '514'], 514]`` ist es zum Beispiel egal dass das ein Wert in einem Dictionary ist.
Letztlich solltest Du aber erst einmal die Datenstruktur überdenken, so dass nicht verschiedene "duck types" in der gleichen Liste stecken.
Und Dein erster Wert ist auch kein gutes Beispiel, denn wenn man das löst, stösst man nicht auf Fragen die zum Beispiel der Wert zu 'RWZ 1' aufwirft. Wie sollte denn da das Ergebnis aussehen? Sollen die beiden 'Absatzkontrolle'-Listen zusammengefasst werden? Wenn ja, soll das Ergebnis vor oder nach der 'Konvertierungsanleitung'-Liste stehen? Falls die Reihenfolge dieser Listen grundsätzlich egal ist und gleiche erste Elemente grundsätzlich zusammengefasst werden sollen, dann sieht das irgendwie eher nach einem Kandidaten für ein Dictionary aus. Auch ein gerne wieder ein `defaultdict` wenn Du Dich dazu durchringen könntest Zahlen auch als solche zu speichern und nicht als Zeichenketten.
Du musst das Problem auf kleinere Teilprobleme runter brechen. Das grosse Problem was Du uns hier zeigst, ist sicher noch nicht das Minimalproblem wo Du Deine Schwierigkeiten hast. Denn für das Zusammenfassen von ``[['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514]`` zu [['Absatzkontrolle', '514'], 514]`` ist es zum Beispiel egal dass das ein Wert in einem Dictionary ist.
Letztlich solltest Du aber erst einmal die Datenstruktur überdenken, so dass nicht verschiedene "duck types" in der gleichen Liste stecken.
Und Dein erster Wert ist auch kein gutes Beispiel, denn wenn man das löst, stösst man nicht auf Fragen die zum Beispiel der Wert zu 'RWZ 1' aufwirft. Wie sollte denn da das Ergebnis aussehen? Sollen die beiden 'Absatzkontrolle'-Listen zusammengefasst werden? Wenn ja, soll das Ergebnis vor oder nach der 'Konvertierungsanleitung'-Liste stehen? Falls die Reihenfolge dieser Listen grundsätzlich egal ist und gleiche erste Elemente grundsätzlich zusammengefasst werden sollen, dann sieht das irgendwie eher nach einem Kandidaten für ein Dictionary aus. Auch ein gerne wieder ein `defaultdict` wenn Du Dich dazu durchringen könntest Zahlen auch als solche zu speichern und nicht als Zeichenketten.
Hallo Patmaster,
vielleicht so ähnlich. Du musst das natürlich für Dich anpassen, und eventuell willst Du Dir auch noch die Reihenfolge der "Listennamen" merken. Und optimal ist das wahrscheinlich nicht, evtl. gibt's da auch bessere Möglichkeiten in Python 2.7 (bin noch mit 2.5/6 unterwegs).
Gruss
Wolfgang
vielleicht so ähnlich. Du musst das natürlich für Dich anpassen, und eventuell willst Du Dir auch noch die Reihenfolge der "Listennamen" merken. Und optimal ist das wahrscheinlich nicht, evtl. gibt's da auch bessere Möglichkeiten in Python 2.7 (bin noch mit 2.5/6 unterwegs).
Gruss
Wolfgang
Code: Alles auswählen
srcList = [['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514]
value_2_name = dict()
for li in srcList:
if type(li) != list:
break
name, val = li
prevVal = value_2_name.setdefault(name, 0)
value_2_name[name] = prevVal + int(val)
for name in value_2_name:
print name, value_2_name[name]
Bezüglich der Kommentare von BlackJack: er hat in allem was er sagt recht. Insofern kann Dir mein Code vielleicht helfen, den Einsatz von setdefault() zu verstehen, ansonsten solltest Du aber Deine Datenstruktur überarbeiten und so nicht weitermachen - das rächt sich bitterlich.
@ws: Wobei der Einsatz von `setdefault()` hier nicht wirklich "richtig" ist. Die Methode setzt den Wert im Dictionary ja auch tatsächlich, dass ist aber unnötig. Ein ``value_2_name.get(name, 0)`` hätte es auch getan.
@patmaster: Muss die letzte Zahl in den Listen denn da überhaupt unbedingt stehen? Denn es sieht zumindest bei den gezeigten Daten so aus, dass das immer die Summe der "Zahlen" in den zweielementigen Listen ist. Damit wäre das redundant und könnte einfach berechnet werden.
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Und gnade einem $Gott, wenn man Unterklassen von `list` nutzt Das `if type(..) != list` sollte man durch `if not isinstance(..)` austauschen.
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
In dem Zusammenhang sollte man auch mal lobend erwähnen, wie einfach sowas in Python ist!patmaster hat geschrieben:ich habe ein Dic das so aussieht:
defaultdict(<type 'list'>, {'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', '300'], ['Absatzkontrolle', '60'], ['Absatzkontrolle', '154'], 514], 'Das Sparschwein im Wandel der Zeiten': [['Konvertierungsanleitung', '60'], ['Sonstiges', '120'], 180], 'Schlager 1': [['Konvertierungsanleitung', '150'], 150], 'RWZ 1': [['Absatzkontrolle', '170'], ['Konvertierungsanleitung', '180'], ['Absatzkontrolle', '60'], 410], 'RWZ 3': [['Absatzkontrolle', '55'], ['Konvertierungsanleitung', '60'], 115]})
Wenn Du eine solche Datenstruktur z.B. mal in Perl versuchtest
http://perldoc.perl.org/perllol.html
wärst Du wahrscheinlich noch schockierter.
Daß Python das ohne zu meckern macht, ist für mich fast schon ein Wunder.
Gruß
Erstmal vielen Dank für eure Antworten.
Ich werde den Code heute gleich mal probieren.
Ja die Zahl muss sein da ich das ganze an ein Django-template Übergebe und dort das Berechnen garnicht oder nur sehr umständlich funktioniert.
Ich weiß das die Datenstruktur ziemlich umständlich ist, aber das Arbeiten mit Django, so scheint es mir erfordet es teilweise Umwege zu gehen um ans Ziel zu kommen.
Ich werde aufjedenfall berichten ob der Code funkioniert...
/edit:
Okay der Code funzt leider nicht wirklich.
Wenn ich dein Beispiel hernehme (ohne was zu ändern) sieht das Ergebnis so aus:
{'Konvertierungsanleitung': 60, 'Absatzkontrolle': 55}
Vlt. soll ich mal Posten wie das gesamte dict am Ende aussehen sollte ?!:
defaultdict(<type 'list'>, {'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', '514'], 514], 'Das Sparschwein im Wandel der Zeiten': [['Konvertierungsanleitung', '60'], ['Sonstiges', '120'], 180], 'Schlager 1': [['Konvertierungsanleitung', '150'], 150], 'RWZ 1': [['Absatzkontrolle', '230'], ['Konvertierungsanleitung', '180'], 410], 'RWZ 3': [['Absatzkontrolle', '55'], ['Konvertierungsanleitung', '60'], 115]})
Also ich will nur Innerhalb der value Liste Listen zusammenfassen bei denen der 1. Wert übereinstimmt und ihre 2. Werte addieren.
Ich werde den Code heute gleich mal probieren.
Ja die Zahl muss sein da ich das ganze an ein Django-template Übergebe und dort das Berechnen garnicht oder nur sehr umständlich funktioniert.
Ich weiß das die Datenstruktur ziemlich umständlich ist, aber das Arbeiten mit Django, so scheint es mir erfordet es teilweise Umwege zu gehen um ans Ziel zu kommen.
Ich werde aufjedenfall berichten ob der Code funkioniert...
/edit:
Okay der Code funzt leider nicht wirklich.
Wenn ich dein Beispiel hernehme (ohne was zu ändern) sieht das Ergebnis so aus:
{'Konvertierungsanleitung': 60, 'Absatzkontrolle': 55}
Vlt. soll ich mal Posten wie das gesamte dict am Ende aussehen sollte ?!:
defaultdict(<type 'list'>, {'Dumme G\xc3\xa4nge revisited': [['Absatzkontrolle', '514'], 514], 'Das Sparschwein im Wandel der Zeiten': [['Konvertierungsanleitung', '60'], ['Sonstiges', '120'], 180], 'Schlager 1': [['Konvertierungsanleitung', '150'], 150], 'RWZ 1': [['Absatzkontrolle', '230'], ['Konvertierungsanleitung', '180'], 410], 'RWZ 3': [['Absatzkontrolle', '55'], ['Konvertierungsanleitung', '60'], 115]})
Also ich will nur Innerhalb der value Liste Listen zusammenfassen bei denen der 1. Wert übereinstimmt und ihre 2. Werte addieren.
@patmaster: Anstelle dieser unübersichtlich verschachtelten Struktur aus "Grunddatentypen" könntest Du eine eigene Klasse schreiben die das kapselt und ein berechnetes Attribut (`property()`) für die Gesamtzahl hat.
Den eigentlich müsste die Struktur -- wie schon gesagt -- noch einen Tick komplexer sein, damit man die zweielementigen Listen verarbeiten kann ohne dass man über die Zahl am Ende der umschliessenden Liste stolpert und dafür eine unschöne Sonderbehandlung programmieren muss.
Der Code von ws funktioniert schon -- er ist halt nur ein Baustein zu einer kompletten Lösung. Ein wenig Arbeit musst Du also schon noch rein stecken.
Ist die Reihenfolge nun eigentlich egal? Also dürfte der Wert zu 'RWZ 1' am Ende auch so aussehen ``[['Konvertierungsanleitung', '180'], ['Absatzkontrolle', '230'], 410]``?
Den eigentlich müsste die Struktur -- wie schon gesagt -- noch einen Tick komplexer sein, damit man die zweielementigen Listen verarbeiten kann ohne dass man über die Zahl am Ende der umschliessenden Liste stolpert und dafür eine unschöne Sonderbehandlung programmieren muss.
Der Code von ws funktioniert schon -- er ist halt nur ein Baustein zu einer kompletten Lösung. Ein wenig Arbeit musst Du also schon noch rein stecken.
Ist die Reihenfolge nun eigentlich egal? Also dürfte der Wert zu 'RWZ 1' am Ende auch so aussehen ``[['Konvertierungsanleitung', '180'], ['Absatzkontrolle', '230'], 410]``?
Ja die Reihenfolge wäre egal.
Ich hab schon versucht das Ganze einwenig anders aufzubauen, aber irgendwie will mir das nicht wirklich gelingen.
Anfangen tut eigenltich alles mit einer Liste von Objecten aus einer Datenbank.
All diese Objekte haben natürlich Attribute, folgende sind wichtig:
Produkt
Minuten
Aktivitaet
Was ich brauche ist etwas (liste, dict, ...) wo 1. nach Produkt gruppiert und innerhalb der "Produktgruppe" nach Aktivität gruppiert wird. Also das alle Minuten die zur gleichen Aktivitaet im gleichen Produkt gehören addiert werden.
Nach Produkt habe ich ja schon Gruppiert nur kam dabei halt dieses Konstrukt raus
Ich hab schon versucht das Ganze einwenig anders aufzubauen, aber irgendwie will mir das nicht wirklich gelingen.
Anfangen tut eigenltich alles mit einer Liste von Objecten aus einer Datenbank.
All diese Objekte haben natürlich Attribute, folgende sind wichtig:
Produkt
Minuten
Aktivitaet
Was ich brauche ist etwas (liste, dict, ...) wo 1. nach Produkt gruppiert und innerhalb der "Produktgruppe" nach Aktivität gruppiert wird. Also das alle Minuten die zur gleichen Aktivitaet im gleichen Produkt gehören addiert werden.
Nach Produkt habe ich ja schon Gruppiert nur kam dabei halt dieses Konstrukt raus
@patmaster: Wenn Du das Problem schon einmal für die Produktgruppe gelöst hast, dann kannst Du das für die Aktivität doch genau so machen -- mit einem `defaultdict`. Und vielleicht gleich beim erstellen der Datenstruktur ohne dass Du das Zwischenergebnis hast, was Du da gezeigt hast.
Na dann:
Ich gebe zu, dass ist schon ein bisschen Fortgeschritten - aber wie ich finde zeigt es mal wieder, wie elegant Python sowas loesen kann.
du kannst natuerlich auch schon gleich versuchen, mehr in der DB machen zu lassen. Gruppieren und Summieren kann die auch. Aber die Syntax dafuer kaeme mir aus dem Kopp nicht richtig raus.
Code: Alles auswählen
import pprint
from operator import itemgetter
from itertools import groupby
data = [
("foo", "mill", 10.0),
("foo", "mill", 20.0),
("foo", "lathe", 10.0),
("bar", "lathe", 5.0),
]
res = {}
for product, activities in groupby(data, itemgetter(0)):
h = {}
for activity, times in groupby(((activity, time) for
_, activity, time in activities), itemgetter(0)):
h[activity] = sum(time for _, time in times)
res[product] = h
pprint.pprint(res)
du kannst natuerlich auch schon gleich versuchen, mehr in der DB machen zu lassen. Gruppieren und Summieren kann die auch. Aber die Syntax dafuer kaeme mir aus dem Kopp nicht richtig raus.
@deets: Als ich deine Lösung gesehen habe, kam gleich der Gedanke defaultdict zu verwenden
Edit: Sorry, hatte die ganze Vorgeschichte garnicht gelesen. Da wurde ja bereits erwähnt defaultdict zu verwenden.
Code: Alles auswählen
from collections import defaultdict
data = [
("foo", "mill", 10.0),
("foo", "mill", 20.0),
("foo", "lathe", 10.0),
("bar", "lathe", 5.0),
]
res = defaultdict(lambda: defaultdict(float))
for product, activity, time in data:
res[product][activity] += time
Zuletzt geändert von Zap am Freitag 11. März 2011, 13:13, insgesamt 1-mal geändert.
@Zap: defenitiv besser. Ich muss gestehen, ich war bei dem groupby etwas ueberrascht, dass es zwar gruppiert, aber dann die Gruppen immer noch den Key enthalten. Allerdings ist das auch logisch, wie soll man's sonst auch machen...
Und deine Loesung ist robuster, denn sie setzt nicht vorraus, dass die Daten sortiert sind.
Und last but not least wusste ich nicht, dass float() == .0 - ich haette da lambda: 0.0 gebaut fuer.
Und deine Loesung ist robuster, denn sie setzt nicht vorraus, dass die Daten sortiert sind.
Und last but not least wusste ich nicht, dass float() == .0 - ich haette da lambda: 0.0 gebaut fuer.