mehrdimensionale Dictionaries

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.
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

mehrdimensionale Dictionaries

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 08:40

Hi zusammen!

Ich bin ein Neuling in Thema Python und bräuchte eure Hilfe in Sachen mehrdimensionale Dictionary.

Mit Perl bin ich groß geworden, doch jetzt will ich auch in die Python Programmierung einsteigen. Doch zu Anfangs tut man da sich wie überall schwer.

Meine Frage an euch lautet. Wie kann ich ein mehrdimensionales Dictionary erstellen und wie kann ich dessen Daten wieder abrufen?

Wie müsste ich eine Dictionary deklarieren wenn es beispielsweise die Daten:
Baum, Äste, Apfel als Keyelemente haben soll und 'rot' als Value eingetragen werden soll?

Und zweitens würde das Dictionary überschieben werden wenn ich in einer Schleife die Dictionaries befüllen lasse wenn ich die gleichen Keyelemente wie dem Vorgänger zuordne. Also beim ersten Druchlauf der Schleife wird ein mehrdimensionales Dictionary mit den Keys 'Baum, Äste, Apfel' abgelegt mit dem Wert 'rot'. Im nächsten durchlauf sind die Keys immer noch die gleichen, aberd er Wert ist auf 'grün' geändert. Würde nun eine weiteres Element dem Dictionary zugefügt werden oder das alte übschrieben werden?

Vielen Dank im voraus!!
Bild
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Beitragvon rayo » Montag 16. Oktober 2006, 08:47

Hi

Code: Alles auswählen

d = {}
d['Baum'] = {}
d['Baum']['Äste'] = {}
d['Baum']['Äste']['Apfel'] = 'rot'

oder

Code: Alles auswählen

d = {'Baum':{'Äste':{'Apfel':'rot'}}}


Den Rest kannst du einfach ausprobieren.

Gruss
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

Beitragvon murph » Montag 16. Oktober 2006, 09:06

also ganz nach feeling:

Code: Alles auswählen

erstes_dic = {'test':'blub'}
zweites_dic = {'test2':'blub'}
haupt_dic = {'erstes_dic':erstes_dic, 'zweites_dic':zweites_dic}
print haupt_dic['erstes_dic']['test']
#ergibt 'blub'

das kannst du jetzt fortführen in dics, die in dics sind, die wiederum in dics sind etc.
den rest musst du selber machen, das sind deine hausaufgaben...
(kleiner tip: dictionairies sind mutabel, genau so wie listen
und wie soll ein dictionairy funktionieren, wenn ein key zweimal vergeben ist?
das wäre ein heftiger designfehler ;-) )
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 10:15

huhu danke!!

und ich habe gehofft, dass Python die 'doppelten' Dictionaries überschreibt. War mir auch fast sicher, aber man kann nie wissen :P

nochmals Danke!!
Bild
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 10:29

hmm ich muss euch erneut belässtigen :)

wenn ich mein Dic folgendermaßen umsetze:

Code: Alles auswählen

GENE_PROMOTER_DIRECTION_STRAND = {gene:{promoter:{direction:strand}}}

gene, promoter, direction und strand sind Variablen die ich aus meine Datenbank lese

Code: Alles auswählen

for gene, promoter, direction, strand in cursor.fetchall():
     GENE_PROMOTER_DIRECTION_STRAND = gene:{promoter:{direction:strand}}}


Gibt es nun eine Möglichkeit in Python dieses Dictionary Stück für Stück in einer Schleife wieder aufzurufen? Das in der ersten Schleife eine Liste von allen beinhalteten Genen von GENE_PROMOTER_DIRECTION_STRAND zurück geliefert wird, etc?

Code: Alles auswählen

Schleife 1
     gene
          Schleife 2
               promoter
                    Schleife 3
                         direction
                         strand
Bild
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Beitragvon pr0stAta » Montag 16. Oktober 2006, 10:38

wenn du weisst wieviele einträge rauskommen
kannst du das ja einfach in 3 for-schleifen lösen

Code: Alles auswählen

dic = {"gene":{"promoter":{"direction":"strand"}}}

for item in dic:
  print item
  for entry in dic[item]:
    print entry
    for another_item in dic[item][entry]:
      print another_item
      print dic[item][entry][another_item]
#ausgabe:
gene
promoter
direction
strand
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 10:41

perfekt!!

Genau das habe ich gesucht!


Danke
Bild
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 11:17

jetzt tritt bei mir leider ein neues Problem auf.

folgende Daten werde durch mein Select Statement aus meiner DB geliefert:

Code: Alles auswählen

geneA - promoter1 - forward - plus
geneA - promtoer2 - forward - plus
geneA - promoter3 - reverse - plus

geneB - promoter1 - reverse - minus
geneB - promoter1 - reverse - minus
geneB - promoter4 - forward - plus
geneB - promoter4 - forward - plus

hier sind 2 Zeilen doppelt (geneB - promoter1 - reverse - minus, geneB - promoter4 - forward - plus) die ich mit Hilfe eines Dictionary eliminieren möchte.
Spalte eins wird in die Variable gene, Spalte2 in promoter, Spalte 3 in direction und Spalte4 in strand gelesen.

Code: Alles auswählen

for gene, promoter, direction, strand in cursor.fetchall():
     dic = {gene:{promoter:{direction:strand}}}

wenn ich mir nun die Ausgabe mit

Code: Alles auswählen

for gene in dic:
  print gene, ' ', dic[gene]

ansehe hätte ich nun folgenden Ausgabe erwartet:

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}

aber statt dessen bekomme ich lediglich:

Code: Alles auswählen

geneB {'promoter4':{'forward':'plus'}


jetzt stellt sich mir die Frage, warum überschriebt er alle anderen Keys, obwohl die nachgestellten keys nicht alle redundant sind? Und ist ein Dictionary überhaupt der richtige Ansatz, wenn ich auf die Ausgabe

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}

abziele?
Bild
BlackJack

Beitragvon BlackJack » Montag 16. Oktober 2006, 11:47

newbie_needs_help hat geschrieben:folgende Daten werde durch mein Select Statement aus meiner DB geliefert:

Code: Alles auswählen

geneA - promoter1 - forward - plus
geneA - promtoer2 - forward - plus
geneA - promoter3 - reverse - plus

geneB - promoter1 - reverse - minus
geneB - promoter1 - reverse - minus
geneB - promoter4 - forward - plus
geneB - promoter4 - forward - plus

hier sind 2 Zeilen doppelt (geneB - promoter1 - reverse - minus, geneB - promoter4 - forward - plus) die ich mit Hilfe eines Dictionary eliminieren möchte.


Warum eliminierst Du die nicht schon in der Datenbankabfrage? ``SELECT DISTINCT ...`` filtert mehrfach vorkommende Datensätze aus.

Spalte eins wird in die Variable gene, Spalte2 in promoter, Spalte 3 in direction und Spalte4 in strand gelesen.

Code: Alles auswählen

for gene, promoter, direction, strand in cursor.fetchall():
     dic = {gene:{promoter:{direction:strand}}}

wenn ich mir nun die Ausgabe mit

Code: Alles auswählen

for gene in dic:
  print gene, ' ', dic[gene]

ansehe hätte ich nun folgenden Ausgabe erwartet:

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}

aber statt dessen bekomme ich lediglich:

Code: Alles auswählen

geneB {'promoter4':{'forward':'plus'}


jetzt stellt sich mir die Frage, warum überschriebt er alle anderen Keys, obwohl die nachgestellten keys nicht alle redundant sind?


Hier werden keine Schlüssel überschrieben, sondern Du erstellst in der ``for``-Schleife ständig neue Dictionary-Objekte. Die Anweisungen lauten: Nimm Daten aus Tabellenzeile, erzeuge (verschachteltes) Dictionary und binde es an den Namen `dic`. Was auch immer vorher an `dic` gebunden war, wird "weggeworfen". Das Ergebnis ist, das `dic` hinterher an ein Dictionary gebunden ist, das die Werte der letzten Zeile aus der Tabelle enthält die in der Schleife verarbeitet wurde.

Und ist ein Dictionary überhaupt der richtige Ansatz, wenn ich auf die Ausgabe

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}

abziele?


Gute Frage. Wenn Du nur Doubletten filtern möchtest, dann kannst Du das mit SQL lösen. Wenn es unbedingt auf der Python-Seite passieren muss und Du keine baumartige Struktur haben möchtest, und danach sieht Deine Beispielausgabe nicht aus, dann kannst Du die Tabellenzeilen in Tupel packen und die in ein `set()` stecken um Doubletten zu eleminieren. Ungetestet:

Code: Alles auswählen

from itertools import imap

def test():
    # ...
    cursor.execute('SELECT ...')
    result = sorted(set(imap(tuple, cursor)))
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 13:06

nein, ich will nicht nur einfach die doppelten Einträge eliminieren (da hätte ich in der Tat distinct genügt). Ich hätte gerne für spätere Anwendungen im Script einen mehrdimensionales Dictionary auf das ich jeder Zeit mit Keys zugreifen kann.

Wie müsste ich denn den Synthax definieren um ein Dictionary zu deklarieren, dass die folgenden Werte speichert.

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}


ich habe nun auch versucht vor der for-Schleife das Dictionary zu deklarieren

Code: Alles auswählen

dic = {}
for gene, promoter, direction, strand in cursor.fetchall():
     dic = {gene:{promoter:{direction:strand}}}

for gene in dic:
  print gene, ' ', dic[gene]

aber leider auch ohne Erfolg.

Ich kenne das so aus Perl da funzt das wunderbar :)

Wie kann ich die Daten in mein Dictionary schrieben/anhängen ohne permanent neue Objekte zu erzeugen?



edit:
Ich habe versucht einen neuen Eintrag an 'dic' zu hängen

Code: Alles auswählen

dic = {}
for gene, promoter, direction, strand in cursor.fetchall():
     dic[gene][promoter][direction] = strand

aber das gab mir leider die Fehlermeldung KeyError: 'xxxx' zurück.

edit:
nun habe ich den quellcode dementsprechend geändert, dass ich nur ein Element an 'dic' hänge

Code: Alles auswählen

for gene, promoter, direction, strand in cursor.fetchall():
     dic[gene] = promoter

for gene in dic:
     print gene, ' ', dic[gene]

aber wenn ich nun einen mehrdimensionales Dictionary erstellen will kommt die Fehlermeldung: keyerror

Code: Alles auswählen

for gene, promoter, direction, strand in cursor.fetchall():
     dic[gene][promoter] = direction


Edit (Leonidas): Code-Tags durch Python-Tags ersetzt.
Bild
BlackJack

Beitragvon BlackJack » Montag 16. Oktober 2006, 14:44

newbie_needs_help hat geschrieben:Wie müsste ich denn den Synthax definieren um ein Dictionary zu deklarieren, dass die folgenden Werte speichert.

Code: Alles auswählen

geneA {'promoter1':{'forward':'plus'}
geneA {'promtoer2':{'forward':'plus'}
geneA {'promoter3':{'reverse':'plus'}
geneB {'promoter1':{'reverse':'minus'}
geneB {'promoter4':{'forward':'plus'}


Das ist kein gültiges Python-Dictionary.

ich habe nun auch versucht vor der for-Schleife das Dictionary zu deklarieren

Code: Alles auswählen

dic = {}
for gene, promoter, direction, strand in cursor.fetchall():
     dic = {gene:{promoter:{direction:strand}}}

for gene in dic:
  print gene, ' ', dic[gene]

aber leider auch ohne Erfolg.


Du hast im Grunde ja auch nichts geändert, ausser das Du ganz am Anfang ein leeres Dictionary ereugst, das genau wie alle anderen in der Schleife dann "weggeworfen" wird. Du solltest wirklich versuchen den Fehler zu verstehen, sonst wirst Du immer wieder solche Probleme bekommen.

Ich kenne das so aus Perl da funzt das wunderbar :)


Nein, auch in Perl funktioniert das so nicht wenn Du immer wieder ein *neues* Hash an einen Namen bindest, anstatt ein bestehendes zu verändern.

Wie kann ich die Daten in mein Dictionary schrieben/anhängen ohne permanent neue Objekte zu erzeugen?

edit:
Ich habe versucht einen neuen Eintrag an 'dic' zu hängen

Code: Alles auswählen

dic = {}
for gene, promoter, direction, strand in cursor.fetchall():
     dic[gene][promoter][direction] = strand

aber das gab mir leider die Fehlermeldung KeyError: 'xxxx' zurück.


Ja, weil in Python nicht auf magische Weise Objekte erzeugt werden. Du musst die Dictionaries auf die dort zugegriffen wird, auch erzeugen und einfügen. Kleines Beispiel für den Fehler:

Code: Alles auswählen

In [53]: a = dict()

In [54]: a['A'] = 'B'

In [55]: a
Out[55]: {'A': 'B'}

In [56]: a['X']['Y'] = 'Z'
---------------------------------------------------------------------------
exceptions.KeyError           Traceback (most recent call last)

/home/marc/<ipython console>

KeyError: 'X'


In `a` gibt es keinen Eintrag für 'X' also kann man auf dem Wert für 'X' auch nicht auf das Element 'Y' zugreifen und dem etwas zuweisen.

Eine Möglichkeit wäre es, sich ein `dict` zu schreiben, das einen "Pfad" mit Schlüsseln und einen Wert in einer Methode entgegen nimmt und leere Dictionaries auf dem Pfad erzeugt, wenn sie noch nicht existieren:

Code: Alles auswählen

from pprint import pprint

source = '''\
geneA-promoter1-forward-plus
geneA-promtoer2-forward-plus
geneA-promoter3-reverse-plus
geneB-promoter1-reverse-minus
geneB-promoter1-reverse-minus
geneB-promoter4-forward-plus
geneB-promoter4-forward-plus
'''.splitlines()


def cursor(lines):
    return (line.split('-') for line in lines)


class PathDict(dict):
    def add_path(self, path, value):
        node = self
        for element in path[:-1]:
            node = node.setdefault(element, dict())
        node[path[-1]] = value


def main():
    result = PathDict()
    for row in cursor(source):
        result.add_path(row[:-1], row[-1])
    pprint(result)


Ausgabe sieht so aus:

Code: Alles auswählen

{'geneA': {'promoter1': {'forward': 'plus'},
           'promoter3': {'reverse': 'plus'},
           'promtoer2': {'forward': 'plus'}},
 'geneB': {'promoter1': {'reverse': 'minus'},
           'promoter4': {'forward': 'plus'}}}


Allerdings solltest Du Dir diesen Ansatz noch mal gut überlegen und nicht versuchen Perl in Python zu programmieren. Verschachtelte Dictionaries werden sehr schnell unübersichtlich und die Funktionen die darauf operieren, sind in den meisten Fällen als Methoden auf Objekten besser aufgehoben.
Benutzeravatar
newbie_needs_help
User
Beiträge: 18
Registriert: Donnerstag 18. Mai 2006, 08:33

Beitragvon newbie_needs_help » Montag 16. Oktober 2006, 15:25

danke für deinen Tipp,

dann werde ich mir noch mal das Kaptile zu den Mehtoden und Dictionary durchlesen und ich bin gespannt, ob ich damit besser fahre.


vielen Dank für eure Hilfe und Geduld!
Bild

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder