Dictionary - Fehlermeldung bei Wertübergabe

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
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

Um einen Vergleich in einem Dictionary machen zu können, muß ich die vierte Spalte dieser Datei (Ausschnitt) bearbeiten.

Code: Alles auswählen

03	127	0135	PATCH-PANEL	PATCH-PANEL,-DIGITUS			
03	127	0172	PATCH-PANEL	PATCH-PANEL,-EQUIP			
03	127	0331	PATCH-PANEL	PATCH-PANEL,-LOGILINK			
03	127	0568	PATCH-PANEL	PATCH-PANEL,-TELEGÄRTNER			
03	128	0000	INDUSTRIAL-ETHERNET,-PASSIV	PATCHKABEL,-KAT.5,-TELEGÄRTNER			
03	128	0000	INDUSTRIAL-ETHERNET,-PASSIV	PATCHKABEL,-KAT.7,-TELEGÄRTNER			
03	128	0000	PATCHKABEL,-KAT.5E,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.5E,-DIGITUS			
03	128	0000	PATCHKABEL,-KAT.5E,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.5E,-DRAKA			
03	128	0000	PATCHKABEL,-KAT.5E,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.5E,-EQUIP			
03	128	0000	PATCHKABEL,-KAT.5E,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.5E,-LOGILINK			
03	128	0000	PATCHKABEL,-KAT.6,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.6,-DRAKA			
03	128	0000	PATCHKABEL,-KAT.6,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.6,-LOGILINK			
03	128	0000	PATCHKABEL,-KAT.7,-ROLLENWARE	PATCHKABEL,-ROLLENWARE,-KAT.7,-DRAKA			
03	128	0135	INTERNET-KAMERAS-/-WEBCAMS	INTERNET-KAMERAS-/-WEBCAMS,-DIGITUS			
03	128	0214	INTERNET-KAMERAS-/-WEBCAMS	INTERNET-KAMERAS-/-WEBCAMS,-GENIUS		
Dabei muß ich den letzten Teil (Herstellernamen) der vierten Spalte verschwinden lassen.
Beispiel:
INTERNET-KAMERAS-/-WEBCAMS,-DIGITUS
INTERNET-KAMERAS-/-WEBCAMS
Da es öfters vorkommt, mehr als nur ein Komma in dem String zu haben, das berücksichtigt werden muß, habe ich ein Konstrukt dazu erstellt

Code: Alles auswählen

with codecs.open(subgroupindex_path, "r") as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")

    subgroupindex = {}
    for line in reader:
       subgroupindex[line[0], line[1]] = line[2]


with codecs.open(basegroup_path, "r") as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")

    daten = []
    for item in reader:        
        if ',' in item[4]:
            y = item[4].count(',')
            y = y - 1

        if y > 1:
            a = item[4].split(',')[:y]
            b = (item[0], a)
            p = subgroupindex.get(b, '---')
        else:
            a = item[4].split(',')[0]
            b = (item[0], a)
            p = subgroupindex.get(b, '---')
Problem dabei, ist dieser Bereich

Code: Alles auswählen

        if y > 1:
            a = item[4].split(',')[:y]
            b = (item[0], a)
            p = subgroupindex.get(b, '---')
Hier kommt als Fehlermeldung:
TypeError: unhashable type: 'list'
Ich habe mir das eigentlich so vorgestellt, daß wie in diesem Beispiel
PATCHKABEL,-ROLLENWARE,-KAT.5E,-DIGITUS
drei Kommas enthalten sind.
Also lasse ich die Kommas im String zählen, ziehe vom Ergebnis -1 ab und definiere den neuen String.
Anschließend möchte ich dieses Ergebnis in einem Dictionary vergleichen können.

Was mache ich falsch, bzw. wo ist mein Denkfehler?

Grüße Nobuddy
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du versuchst ein Objekt, welches nicht gehasht werden kann (hier eine Liste) als Schlüssel für ein Dict zu verwenden. Das passiert in der zweiten Zeile:

Code: Alles auswählen

b = (item[0], a)
p = subgroupindex.get(b, '---')
``b`` ist eben nicht ``hashable`` - Du willst es aber als Schlüssel verwenden. Zwar ist das hier nur eine Abfrage, die kann aber eh nicht sinnvoll sein, da so ein Schlüssel natürlich auch nicht in ein Dict eingefügt werden kann ;-)

Beispiele:

Code: Alles auswählen

>>> l = [1, 2, 3]
>>> d = {}
>>> d.get(l)
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    d.get(l)
TypeError: unhashable type: 'list'
>>> foo = ("bar", l)
>>> d = {}
>>> d.get(foo)
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    d.get(foo)
TypeError: unhashable type: 'list'
>>> type(foo)
2: <class 'tuple'>
Der Fehler dürfte übrigens auch im ``else``-Zweig auftreten ;-)

Was mir aber nicht klar ist: Wieso machst Du da so viele Verrenkungen bezüglich des Parsens? Woran erkennst Du denn exakt eine Firma? Dafür muss es doch Regeln geben! Mir ist das bisher unklar, aber das sollte def. eleganter gehen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Nobuddy hat geschrieben:Was mache ich falsch, bzw. wo ist mein Denkfehler?
Ich finde den ganzen Ansatz zu kompliziert. Ich würde einfach den String mit split auseinandernehmen und dabei das Komma als Trenner wählen. Anschließend packt man dann alles ohne den letzten Teil wieder zusammen.

Code: Alles auswählen

>>> data = 'PATCHKABEL,-ROLLENWARE,-KAT.7,-DRAKA'
>>> ','.join(data.split(',')[:-1])
'PATCHKABEL,-ROLLENWARE,-KAT.7'
Falls es vorkommen kann, dass kein Komma im String vorhanden ist, dann sollte man das vorher feststellen und in dem Fall gar nichts tun.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ja, manches mache ich wirklich kompliziert, das merke ich meistens hinterher ... :wink:

Hyperion, die Regel ist die, daß in Spalte 4 immer als letztes der Hersteller, getrennt durch ein ',-' enthalten ist.

Meine Lösung, welche funktioniert

Code: Alles auswählen

with codecs.open(subgroupindex_path, "r") as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")

    subgroupindex = {}
    for line in reader:
       subgroupindex[line[0], line[1]] = line[2]


with codecs.open(basegroup_path, "r") as infile:
    reader = csv.reader(infile, delimiter="\t", quotechar="^")

    daten = []
    for item in reader:
        if ',-' in item[4]:
            y = item[4].count(',-')
            a = item[4].split(',-')[y]
            z = item[4].replace(',-' + a, '')

        b = (item[0], z)
        p = subgroupindex.get(b, '---')
Allerdings ist die Lösung von /me, kürzer und eleganter.
Werde diese ausprobieren!
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Das geht meiner Meinung nach noch eleganter. ;)

Code: Alles auswählen

In [2]: data = 'PATCHKABEL,-ROLLENWARE,-KAT.7,-DRAKA'

In [3]: data.rpartition(',')[0]
Out[3]: 'PATCHKABEL,-ROLLENWARE,-KAT.7'
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Nobuddy hat geschrieben:Werde diese ausprobieren!
Eine Alternative könnte es auch noch sein das letzte Komma im String zu bestimmen und dann mit dem passenden Slice zu arbeiten.

Code: Alles auswählen

pos = data.rfind(',')
if pos >= 0:
    data = data[:pos]
Da ist die Prüfung auf ein vorhandenes Komma gleich eingebaut.

Edit: @nomnom: An partition hatte ich ja gedacht, aber rpartition war mir entfallen. Das ist für mich die beste Variante.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

/me, habe zuerst Deinen Vorschlag ausprobiert

Code: Alles auswählen

pos = data.rfind(',')
if pos >= 0:
    data = data[:pos]
, was schon wesentlich kürzer als mein Konstrukt ist und prima funktionierte.

Jedoch der Tip von nomnom, ist nochmals kürzer und funktioniert auch prima, wie Du selbst geschrieben hast.

Code: Alles auswählen

data.rpartition(',')[0]
Mit dem

Code: Alles auswählen

data = 'PATCHKABEL,-ROLLENWARE,-KAT.7,-DRAKA'
data = data.rpartition(',')[-1].replace('-', '')
erhalte ich dann diese Ausgabe
'DRAKA'
Danke für Euren Input! :wink:

Grüße Nobuddy
Antworten