Zelleninhalt auf Zeilen verteilen

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
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey zusammen,

ich mal wieder.

Ich habe folgendes Problem. Ich möchte gern Daten in eine MySQL Datenbank landen, aber die Daten sind "schlecht formatiert".
Sie sehen im Prinzip so aus:
Spalte 1 | Spalte 2
Buch 1 | Autor1; Autor2; Autor3; Autor4
Buch 2 | AutorX; AutorY; AutorZ
usw.

Jetzt möchte ich es gern umwandeln zu
Spalte 1 | Spalte 2
Buch 1 | Autor1
Buch 1 | Autor2
Buch 1 | Autor3
Buch 1 | Autor4

Nun zur Theorie:
Jetzt könnte ich doch die Spalte 2 in eine Liste laden (; - getrennt) und Sie dann zählen (Anzahl der Elemente = N).
Und dann N Zeilen schreiben mit jeweils Buch 1 in der ersten Spalte und dann dem i ten (i=1...N) Element in Spalte 2

Was meint Ihr? Ist das so umsetzbar?

LG
Kid
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: umsetzbar ist das wohl, aber ob das auch gut ist, ist eine andere Frage. Das Zählen ist in Python unnötig, da man über Listen direkt iteriert.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi Sirius3,
Sirius3 hat geschrieben:umsetzbar ist das wohl, aber ob das auch gut ist, ist eine andere Frage.
Wieso sollte es nicht gut sein? Es macht doch Sinn so eine relationale Datenbank aufzubauen oder? X Autoren in einer Zelle macht doch erstmal wenig Sinn.
Oder meinst Du noch was anderes?

LG
BlackJack

@kidchino: Ich denke Sirius3 meinte das Zählen, also `N` und `i` sollten als Variablen nicht im Code auftauchen, die sind unnötig. Und auch bei der Beschreibung im Text ist das etwas umständlich.

Nächste Frage: was sind 'Buch 1' für Werte? Zeichenketten oder eine ID in eine `publication`-Tabelle wo dann der Buchtitel als Zeichenkette steht?
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: ich meinte, der Datenbankentwurf sieht mir sehr danach aus, als ob sowohl Spalte 1 als auch Spalte 2 Strings sind, mit dem Namen des Buches und dem Namen des Autors. "Spalte 1" ist auch ein schlechter Name für eine Spalte. Nun kann es ja durchaus vorkommen, dass Bücher gleich heißen (z.B. 1914), oder Autoren den selben Namen haben.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

kidchino hat geschrieben:Was meint Ihr? Ist das so umsetzbar?
Wenn du das normalisieren willst (was eine gute Idee ist), dann brauchst du eine Tabelle BUCH, eine Tabelle AUTOR und eine Verbindungstabelle BUCH_AUTOR.

Die Tabelle BUCH enthält alle Informationen zu einem Buch außer dem Autor.
Die Tabelle AUTOR enthält alle Informationen zu einem Autor außer den Büchern die er geschrieben hat.
Die Tabelle BUCH_AUTOR enthält in jeweils einem Datensatz die IDs eines Buches und eines Autors.

Damit kannst du dir dann über eine simple Abfrage alle Autoren anzeigen lassen die an einem Buch mitgeschrieben haben und umgekehrt natürlich auch für einen Autor alle Bücher anzeigen lassen an denen er mitgearbeitet hat. Eine Änderung der Autorendaten wie z.B. "gestorben am" erfordert dann nur eine Änderung in der AUTOR-Tabelle und sonst nirgendwo.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey zusammen,
so sehen die Rohdaten eigentlich aus:

Code: Alles auswählen

J	WONDRATSCHEK, H; JEITSCHKO, W				WONDRATSCHEK, H; JEITSCHKO, W			TWIN DOMAINS AND ANTIPHASE DOMAINS	ACTA CRYSTALLOGRAPHICA SECTION A			English	Article									UNIV KARLSRUHE,INST CRYSTALLOG,D-7500 KARLSRUHE,FED REP GER; DUPONT CO,DEPT CENT RES & DEV,WILMINGTON,DE 19898			JEITSCHKO, Wolfgang/D-7754-2012	JEITSCHKO, Wolfgang/0000-0002-1333-4523				23	97	97	MUNKSGAARD INT PUBL LTD	COPENHAGEN	35 NORRE SOGADE, PO BOX 2148, DK-1016 COPENHAGEN, DENMARK	0108-7673			ACTA CRYSTALLOGR A	Acta Crystallogr. Sect. A		1976	32	JUL1					664	666		10.1107/S056773947600137X		3	Crystallography	Crystallography	BY927	WOS:A1976BY92700019		
Ich hatte ein kleines Skript geschrieben, welche eine neue Datei erstellt nur mit Elemement 58 und 1 also dann so aussehen würde:

Code: Alles auswählen

WOS:A1976BY92700019	WONDRATSCHEK, H; JEITSCHKO, W
Die Spalte 1 heißt dann bei mir "paperID", die Spalte 2 würde ich "author" nennen.
Die paperId, die ich vorher der Einfachheit halber als Buch bezeichnet hatte, ist leider ein String, aber einzigartig.
Dass die Autoren gleiche Namen haben ist leider möglich. Es gibt auch eine einzigartige AutorenID, aber die ist erst vor ein paar Jahren eingeführt und daher nun teilweise in meinen Daten vorhanden.
Dies nehme ich erstmal so hin.
VG
BlackJack

@kidchino: Die IDs von denen wir sprechen sind nicht aus deinen Daten sondern die würde man in der Datenbank einführen. Du möchtest in einem sinnvollen DB-Entwurf in aller Regel keine redundanten Zeichenkettendaten in den Tabellen haben. Man hat eigentlich fast immer einen synthetischen Schlüssel in den Tabellen der sich nicht aus den Daten herleitet die im Datensatz stehen. Ausnahmen davon sind eher selten.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey,

danke erstmal schon für die viele Antworten in so kurzer Zeit.

Ich würde dann einfach eine dritte auto-inkremental Spalte einfügen (1,2,3...bis zur Unendlichkeit und noch viel weiter) [Da hat wohl einer nen Clown gefrühstückt heute] und diese dann über die paperID spalte in den anderen Tabellen einfügen.

Aber nochmal zurück zum Anfang. Würde das so sinnvoll gehen in Python? Und bekomme ICH es auch hin?

VG
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey zusammen,

habe es heute endlich mal geschafft mich an das Skript zu machen.
Irgendwie, vielleicht liegts an der Uhrzeit ;), aber ich hab so gar keine Idee wie ich die Schleife richtig reinbekomme und wo ich ansetzen muss.
Aktuell ist mein Output ja immer nur row [0] und das erste Element in row[1].

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys, re

datei = 'C:/Skripttesten/test/output/Nur Adress ohne Eckige Klammer/test.csv' 

csv.field_size_limit(150000000) 
liste = [] 
gesamte_datei = open('C:/Skripttesten/test/output/Zeilenweise.csv', "wb")  
with open(os.path.join(datei), "rb") as f: 
    reader = csv.reader(f, delimiter="\t")
    for row in reader:   
        autoren_spalte = row[1].split(";")
                            
        row_umgestellt = [row[0], autoren_spalte[0]]
        print(hilfs_var)
        
        liste.append(row_umgestellt)                 
                  
writer = csv.writer(gesamte_datei,  delimiter = "\t")
writer.writerows(liste)
print("Ende - Datein wurde neu formatiert in ", gesamte_datei)
Ich würde jetzt soetwas versuchen.

Code: Alles auswählen

laenge_spalte_zwei = len(autoren_spalte)
        i = 0
        while i < laenge_spalte_zwei+1:
            hilfs_var = [row[0], autoren_spalte[i]]
            if i = laenge_spalte_zwei+1
Kann mir jemand einem Tipp geben.
Irgendwie denke ich, dass while auch nicht das richtige ist.
LG
BlackJack

@kidchino: Über die Elemente einer Liste kann man mit ``for`` iterieren. Das sind Grundlagen…
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi Blackjack,
BlackJack hat geschrieben:@kidchino: Über die Elemente einer Liste kann man mit ``for`` iterieren. Das sind Grundlagen…
Da hast Du vollkommen recht. War wohl doch zu spät gestern und zu wenig schlaf.

Was meint Ihr hierzu?

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys, re

datei = 'C:/Skripttesten/test/output/Nur Adress ohne Eckige Klammer/test.csv' 

csv.field_size_limit(150000000) 
liste = [] 
gesamte_datei = open('C:/Skripttesten/test/output/Zeilenweise.csv', "wb")  
with open(os.path.join(datei), "rb") as f: 
    reader = csv.reader(f, delimiter="\t")
    for row in reader:   
        autoren_spalte = row[1].split(";")
        laenge_spalte_zwei = len(autoren_spalte)
        i = 0
        for i in range (0,laenge_spalte_zwei, 1):
            
            print (i)
            neue_anordnung = [row[0], autoren_spalte[i]]
            i=i+1
            print(neue_anordnung)
            liste.append(neue_anordnung)
                  
writer = csv.writer(gesamte_datei,  delimiter = "\t")
writer.writerows(liste)
print("Ende - Datein wurde neu formatiert in ", gesamte_datei)
Spricht das was dagegen?
LG
KID
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: Zeilen 14 und 19 sind total überflüssig, weil i ja schon von der for-Schleife gesetzt wird. Das drei-parametrige range hätte genausogut mit einem Parameter geschrieben werden können. Aber, Zeile 15 ist ein Anti-Pattern, weil man direkt über die autoren_spalte iterieren kann.
Ungetestet:

Code: Alles auswählen

liste.extend([row[0], a] for a in row[1].split(';'))
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi Sirius3,
danke!
Sirius3 hat geschrieben:@kidchino: Zeilen 14 und 19 sind total überflüssig, weil i ja schon von der for-Schleife gesetzt wird.
Auf jeden Fall ! Danke
Sirius3 hat geschrieben:@kidchino: Das drei-parametrige range hätte genausogut mit einem Parameter geschrieben werden können.
Stimmt, ja! Danke
Sirius3 hat geschrieben:@kidchino: Aber, Zeile 15 ist ein Anti-Pattern, weil man direkt über die autoren_spalte iterieren kann.
Aber damit kann ich leider nichts anfangen :( Ich google gerade nach Anti-Pattern, finde aber nicht das, was für mich ausreichend verständlich ist.
Das ist ganz okay, denke ich: http://lignos.org/py_antipatterns/.

Ist es so besser?

Code: Alles auswählen

...
 laenge_spalte_zwei = len(autoren_spalte)
        for i in range (laenge_spalte_zwei):
            neue_anordnung = [row[0], autoren_spalte[i]]
            liste.append(neue_anordnung)
...
LG
kid
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Sirius3 hat geschrieben:@kidchino: Ungetestet:

Code: Alles auswählen

liste.extend([row[0], a] for a in row[1].split(';'))
Das verstehe ich zwar schon, aber kann ich nicht so einfach nachbauen bzw. nachvollziehen. Trotzdem danke.

Seht Ihr bei meiner Version noch großes Fehlerpotential irgendwo?
LG

BTW: Hammer, wie viele Fehler ich beim Schreiben immer mache... Sorry dafür. Teilweise finde ich das ziemlich spannend und schreib recht schlecht (was ich nicht kann) und freue mich wie ein Keks, wenn ich die Skripte (mehr oder weniger allein ;)) zum laufen bringe.
DaftWullie
User
Beiträge: 37
Registriert: Donnerstag 17. Mai 2012, 21:28

@kidchino
kidchino hat geschrieben:Ich google gerade nach Anti-Pattern, finde aber nicht das, was für mich ausreichend verständlich ist.
Das ist ganz okay, denke ich: http://lignos.org/py_antipatterns/.
Wenn Du einfach mal im Forum stöberst, findest Du seehr viel zum Thema Anti-Pattern, zum Beispiel hier.
Antworten