Ändern von Bezeichnungen in einer Liste

Code-Stücke können hier veröffentlicht werden.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

Guten Morgen,

ich habe dieses Ergebnis:

{
"List1": [
{
"description": "What ever",
"enabled": true,
"id": "1234",
"name": "abc"
},
{
"description": "What ever2",
"enabled": true,
"id": "3456",
"name": "def"
},
{
"description": "What ever 3",
"enabled": true,
"id": "6789",
"name": "ghi"
}
],
"Liste 2": []
}

aus einer anderen Abfrage und muss an dieser Stelle das Wertepaar 'enabled : true' aus der Liste entfernen und auch die Bezeichnungen der drei weiteren Wertepaare verändern.

Wenn ich das richtig verstanden habe, so sind die Wertepaare in einem Dictionary und das Dictionary in einer Liste, richtig?

Wenn ich also nur die Keys der List1 ausgeben möchte, so sollte dies doch mit

for key in t['List1']:
print(key)

nur die Key des Dictionaries ausgegeben werden.Ich erhalte jedoch als Ausgabe die Wertepaare

{'enabled': 'true', 'description': 'What ever', 'name': 'abc', 'id': '1234'}
{'enabled': 'true', 'description': 'What ever2', 'name': 'def', 'id': '3456'}
{'enabled': 'true', 'description': 'What ever 3', 'name': 'ghi', 'id': '6789'}


Wie kann ich hier zu meinem gewünschten Ergebnis kommen bzw, wo habe ich meinen Denkfehler?

Danke und Grüße
Andreas
BlackJack

@andyritter: Du denkst eine Verschachtelung zu kurz. Probier das doch einfach mal in einer Pythonshell aus:

Code: Alles auswählen

In [25]: data
Out[25]: 
{'List1': [{'description': 'What ever',
   'enabled': True,
   'id': '1234',
   'name': 'abc'},
  {'description': 'What ever2', 'enabled': True, 'id': '3456', 'name': 'def'},
  {'description': 'What ever 3',
   'enabled': True,
   'id': '6789',
   'name': 'ghi'}],
 'Liste 2': []}

In [26]: data['List1']
Out[26]: 
[{'description': 'What ever', 'enabled': True, 'id': '1234', 'name': 'abc'},
 {'description': 'What ever2', 'enabled': True, 'id': '3456', 'name': 'def'},
 {'description': 'What ever 3', 'enabled': True, 'id': '6789', 'name': 'ghi'}]
Das ist eine Liste mit Wörterbüchern. Eine Liste hat keine Schlüssel sondern Elemente. Der Name der Laufvariable ist also falsch. Du musst eine Schleife über die Elemente schreiben und dann in dieser Schleife das was Du machen möchtest mit jedem Element machen.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@Blackjack Danke für den Hinweis, dass ich eine Verschachtelung zu kurz denke.
Ich werde mich weiter daran versuchen :wink:

Was sagt denn das In [25]: und Out[25]: in Deinem Code aus?
BlackJack

@andyritter: Dass das hinter In[25]: die 25. Eingabe in der IPython-Shell war und hinter Out[25]: die dazugehörige Ausgabe. In der normalen Python-Shell sieht man >>> vor der Eingabe und nichts vor der Ausgabe.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

andyritter hat geschrieben:(...) und muss an dieser Stelle das Wertepaar 'enabled : true' aus der Liste entfernen und auch die Bezeichnungen der drei weiteren Wertepaare verändern.
Hier noch vorab ein Hinweis, weil das ein häufiger Anfängerfehler ist: Nimm besser nicht direkt Veränderungen an den bestehenden Dictionaries vor, indem du Lösch- und Hinzufüge-Operationen darauf durchführst, sondern ziehe dir die benötigten Daten in ein neu erstelltes Dict rüber, wo die du sie den angepassten Schlüsselnamen zuordnest. Du hast dann also im Ergebnis komplett neue Objekte, auf denen weitergearbeitet werden kann.

Das ist ein übliches Vorgehen und der zusätzliche Speicherverbrauch ist in den allermeisten Anwendungsfällen vernachlässigbar. Der Vorteil der geringeren Komplexität im Code überwiegt hier.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJack
Danke für die Info.

@snafu
danke für diesen wertvollen Tipp
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

ich stehe, bzw sitze, glaube ich immer noch auf der Leitung.... :?

wenn ich also in der Liste Dictionaries habe und die Anzahl dieser Dictionaries variiert bei der Abfrage, dann müsste ich doch eine Schleife um das ganze bauen, die beim Durchlauf immer um 1 erhöht wird, bis es keine weitere Zeile mehr gibt, oder?

Muss ich dazu die Anzahl der Zeilen (Dictionaries in der Liste) zuerst noch abfragen?

oder denke ich immer noch eine Ebene zu kurz?
BlackJack

@andyritter: Jetzt denkst Du eine Ebene zu kompliziert. Du musst da nirgends die Anzahl abfragen oder etwas hochzählen, Du kannst direkt über die Elemente in der Liste iterieren. Das machst Du doch in der ``for``-Schleife sogar schon, nur das es halt keine Schlüssel sind, sondern ganze Wörterbücher über die diese Schleife iteriert.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJack: Jetzt bin ich verwirrt... wie soll das funktionieren?
BlackJack

@andyritter: Eine ganz normale ``for``-Schleife halt. Das sind absolute Grundlagen. Und Du hast doch selbst weiter oben schon Quelltext gezeigt der genau das macht.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJack: Sorry, ich hab mich wohl nicht deutlich erklärt... :oops:

Die Schleife ist ja schon vorhanden, da stimme ich Dir zu, allerdings komme ich mit der Bearbeitung der Dictionaries in der Liste kein Stück weiter.

Kannst Du mit bitte in einem Beispiel (Codeschnipsel) Deine Vorgehensweise darstellen?

Danke schön
BlackJack

@andyritter: Na in der Schleife kannst Du in jedem Durchlauf mit dem aktuellen Wörterbuch anstellen was Du willst. Du gibst es in Deinem Beispiel mit `print()` aus. Mach stattdessen halt das was Du machen willst.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@BlackJack: Wenn ich also innerhalb der Schleife das Dict verändern möchte, so soll ich das direkt tun. Leider ist mein Ansatz da wohl wieder zu kurz gedacht

mit dem Script

for items in t['List1']:
if "enabled" in items:
del "enabled"

gibt es diese Fehlermeldung

There's an error in your prgogram: *** can't delete literal(dictionary Iteration.py, line 60)

daher kann ich mit deiner Empfehlung ".. mach was du möchtest..." leider nicht viel anfangen..
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Es muss nicht ``del "enabled"``, sondern ``del items["enabled"]`` heißen. Denn Python weiß nicht auf magische Weise, worauf sich das "enabled" bezieht, nur weil es eine Zeile vorher in Zusammenhang mit dem Item benutzt wurde. Übrigens würde ich es "item" anstelle von "items" nennen.

Weiterhin scheinst du meinen Hinweis, explizites Löschen zu vermeiden, nicht verstanden zu haben. Du hattest dich zwar dafür bedankt, aber wendest ihn trotzdem nicht an.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

@snafu: Vielen Dank für Deinen Codeschnipsel. Vielleicht sollt ich hier noch etwas zur weiteren Verarbeitung und der Quelldaten posten.

Die Quelldaten werden regelmäßig von einem Server abgezogen und dann weiterverarbeitet um einen Teil der Daten in einer Tabelle in einer Datenbank einzufügen. Daher kann dieser Teil der Quelldaten ohne weiteres gelöscht werden, weil für eine weitere Verarbeitung definitiv nicht benötigt.

Der Hinweis mit der Kopie ist schon bei mir angekommen, doch ich benötige die Quelldaten ja nicht weiter, daher kann ich das meiner Meinung nach auch wirklich löschen.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@andyritter: es geht nicht darum, was Du jetzt mit diesen Datenstrukturen machst, sondern darum, was Du irgendwann einmal damit machst, und dann ist es immer sinnvoll, beim Programmieren so wenig Kollateralschäden anzurichten wie geht. Zudem Du weiter oben geschrieben hast, dass Du die anderen Keys noch umbenennen willst, so dass von Deinem ursprünglichen Wörterbuch nichts übrig bleibt.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1011
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Manchmal sind die Daten einfach zu sehr verschachtelt und man verliert schnell den Überblick. Zumindest geht es mir so.
Ich versuche das dann immer in der Repl auseinander zu nehmen. Wichtig ist, dass man genau weiß was für ein Datentypen vorliegen und welche bei der Iteration ausgegeben werden, damit man die passenden Methoden verwendet und überhaupt weiß was man dort macht. Also du hast ein dict, in dem der Schlüssel der Name der Liste ist und der Wert eine Liste mit Dicts.

Mit dict.items() liefert eine Tupel mit key, value (generator in Python3). Falls es Python2.7 ist, sollte man dict.iteritems() verwenden um Speicher zu sparen. Iteriert man über value nochmals, bekommt man die Elemente aus der Liste, die dicts sind. Dann noch im Hinterkopf behalten, dass dicts mutable Datentypen sind. D.h. Methoden, die du darauf anwendest, verändern das Objekt innerhalb der Liste. Die Liste ist natürlich auch mutable.

Code: Alles auswählen

l = {'List1': [{'description': 'What ever',
            'enabled': False,
            'id': '1234',
            'name': 'abc'},
           {'description': 'What ever2',
            'enabled': True,
            'id': '3456',
            'name': 'def'},
           {'description': 'What ever 3',
            'enabled': True,
            'id': '6789',
            'name': 'ghi'}],
 'Liste 2': []}

def change_state(data, id, enabled=False):
    for key, value in data.items():
        for item in value:
            if item.get('id') == str(id):
                item.update({'enabled': enabled})

change_state(l, 1234, True)
print([element for key, value in l.items() for element in value if element.get('id') == '1234'])
Am besten baust du dir eine Klasse um die Daten herum.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

DeaD_EyE hat geschrieben:Am besten baust du dir eine Klasse um die Daten herum.
Falls damit gemeint ist, dass bloß triviale Getter und Setter für die einzelnen Schlüssel gebastelt werden sollen, um an den zugehörigen Wert zu kommen, dann würde ich den Einsatz von Klassen hier *nicht* empfehlen, weil ich den Mehrwert in diesem Fall für fragwürdig halte. Die Umsetzung deines Vorschlags findet man zwar oft z.B. in der Java-Welt, aber in Python ist es üblich, dass ein nacktes Dictionary Teil der API ist und dass deshalb keine Wrapper-Klasse um die Daten gebaut wird.

Falls etwas anderes gemeint ist, dann wären Details, wie diese Klasse aussehen soll bzw was sie tun soll, hilfreich.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

andyritter hat geschrieben:Der Hinweis mit der Kopie ist schon bei mir angekommen, doch ich benötige die Quelldaten ja nicht weiter, daher kann ich das meiner Meinung nach auch wirklich löschen.
Bei meiner Begründung stand die geringere Komplexität des Codes im Vordergrund, die man durch das Weglassen von `del`-Statements erreicht. Wie gesagt: Der zusätzliche Speicherverbrauch wirkt sich oft nicht spürbar aus, sodass der Vorteil, den man durch `del` zu haben glaubt, in der Praxis eigentlich nicht zum Tragen kommt. Zumal genau genommen gar nicht garantiert ist, wann ein durch `del` zum Löschen freigegebenes Objekt auch wirklich aus dem Speicher gelöscht wird. Das kann prinzipiell viel später passieren, als du denkst.

Aber gut: Letztlich ist es eine Frage des persönlichen Stils, ob man neue Dictionaries anlegt (und dadurch Codezeilen einspart) oder ob man lieber bereits bestehende Dictionaries verändert. Richtig schlecht wird der Einsatz von `del` erst bei Listen, weil dann unter Umständen (je nach Implementierung) intern eine Neuordnung der Daten erfolgen muss, wenn man mit `del` irgendwelche Elemente herausgepflückt hat. Und das ist dann gar nicht mehr so vorteilhaft in Hinblick auf die Performance des Programms.
andyritter
User
Beiträge: 29
Registriert: Montag 7. März 2016, 16:27

Vielen Dank für eure Erläuterungen,
ich habe mich dazu entschieden, die Datensätze direkt in die Datenbank zu schreiben ohne zuvor etwas zulöschen oder anzupassen.

for item in t['tenants']:
osp_tenants_tenant_id = item['id']
osp_tenants_name = item['name']
osp_tenants_description = item['description']
print(osp_tenants_tenant_id)
print(osp_tenants_name)
print(osp_tenants_description)
cur.execute("""INSERT INTO osp_tenants (name, tenant_id, description) VALUES (%s, %s, %s)""",(osp_tenants_name, osp_tenants_tenant_id, osp_tenants_description)

was mir hierbei noch nicht gelungen ist, ist die Prüfung der Tabelle mit IF EXISTS. das ist dann jedoch eine neuer Thread, oder?
Antworten