CSV-Dateien miteinander vergleichen und ergänzen

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
mapo
User
Beiträge: 6
Registriert: Montag 1. November 2021, 14:14

Moin Zusammen,
ich habe folgendes Problem: Ich habe zwei CSV-Dateien mit verschiedenen Daten, die jedoch als Gemeinsamkeit Emailadressen beinhalten. Nun soll das Programm herausfinden, ob eine E-Mail in der 1ten Datei und in der 2ten Datei vorhanden ist. Ist dies der Fall sollen die Daten von der 2ten Datei der 1 Datei hinzugefügt werden. Mein erster Entwurf sieht so aus:

Code: Alles auswählen

import csv
import json
kontakte = {}

f = open('MAListeV.csv', 'r', newline='')

daten_csv = csv.DictReader(f, delimiter=',')

with open('TestdatenO.csv', 'r', newline='') as csv_datei:
    dialect = csv.Sniffer().sniff(csv_datei.readline())
    csv_datei.seek(0)

    reader = csv.reader(csv_datei, dialect)
    
    kopfzeile = next(reader)
    
    for zeile in reader:
        eintrag = {
            kopfzeile[1]: zeile[1],
            
          
        }
    name = f' {zeile[1]}'
    kontakte[name] = eintrag
print(json.dumps(kontakte, indent=4))
    
for row in daten_csv:
    print(row['Email'])

if zeile[1] in row['Email']:
    print("Funktioniert")
    
Leider ist das Problem, dass die Abgleichung nur funktioniert, wenn in beiden Dateien nur eine Email steht. Es soll aber natürlich auch gehen wenns mehrere sind. Theoretisch müsste das Programm die 1te Zeile aus Datei1 mit jeder Zeile einzeln aus Datei2 vergleichen. Dann die 2te Zeile aus Datei mit jeder Zeile aus Datei2. Falls es einen Treffer geben sollte, dann hört der Schritt natürlich auf und die Informationen sollen in einer neuen Datei zusammengefügt werden. Ich hoffe Ihr versteht mein grobes Problem und habt eine Idee, inwiefern man die Daten miteinander korrekt abgleichen könnte.

Lg und vielen Dank im Voraus!
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mapo: Der Code ist wenig übersichtlich geschrieben. Da solltest Du dran arbeiten. Zum Beispiel nicht eine Datei öffnen, einen csv-Reader erstellen und dann über die Hälfte der Programmzeilen die gar nichts damit machen, und dann erst der Code der das tatsächlich benutzt.

Bei der einen Datei verwendest Du ``with``, bei der anderen nicht. Warum? Die wird nicht sauber geschlossen. Nicht einmal mit einem manuellen `close()`.

Beim lesen von ``TestdatenO.csv`` wird am Ende ausschlieslich der letzte Eintrag in `kontakte` eingetragen, weil das *hinter* der Schleife steht und nicht im Schleifenkörper. Falls die Datei ausser der Kopfzeile leer ist, führt das zudem zu einer Ausnahme weil `eintrag` dann undefiniert ist. Ich vermute mal das sollte *in* die Schleife.

Dann lassen sich da benannte Zwischenergebnisse einfach einsetzen, und dann kann man aus der Schleife eine einfache „dict comprehension“ machen.

Beim Verarbeiten von ``MAListeV.csv`` ist wieder das gleiche Problem: Du prüfst *nach* der Schleife etwas mit dem letzten Datensatz aus der Datei was wohl für *jeden* Datensatz geprüft werden sollte. Und Du tust das mit einer Schleifenvariablen aus der Verarbeitung der vorhergehenden Datei, also auch wieder nur mit dem letzten Datensatz und den Namen `zeile` gibt es da auch nur falls die Schleife der ersten Datei tatsächlich mindestens einmal durchlaufen wurde. Sonst gibt es eine Ausnahme weil der Name nicht definiert ist.

Der Test mit ``in`` ist ziemlich sicher falsch, denn Du willst ja nicht wissen ob eine E-Mail *in* einer anderen enthalten ist, sondern ob die *gleich* sind. E-Mail-Adressen können auch in anderen E-Mail-Adressen enthalten sein und unterschiedlich sein.

Nicht funktionierender Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import json


def main():
    with open(
        "TestdatenO.csv", "r", newline="", encoding="utf-8"
    ) as csv_datei:
        dialect = csv.Sniffer().sniff(csv_datei.readline())
        csv_datei.seek(0)
        reader = csv.reader(csv_datei, dialect)
        kopfzeile = next(reader)
        kontakte = {
            f" {zeile[1]}": {kopfzeile[1]: zeile[1]} for zeile in reader
        }

    print(json.dumps(kontakte, indent=4))

    with open("MAListeV.csv", "r", newline="", encoding="utf-8") as file:
        daten_csv = csv.DictReader(file, delimiter=",")
        for row in daten_csv:
            print(row["Email"])
            #
            # FIXME `zeile` gibt es hier nicht, und es würde auch keinen Sinn
            # machen sich hier auf eine *möglicherweise* existierende
            # Laufvariable aus einer vorher bereits beendeten Schleife zu
            # beziehen.
            # 
            if zeile[1] == row["Email"]:
                print("Funktioniert")


if __name__ == "__main__":
    main()
Eine doppelt verschachtelte Schleife würde wahrscheinlich funktionieren, hätte aber ein gruseliges Laufzeitverhalten. Man würde erst eine der Dateien einlesen und dort die E-Mail-Adresse(n) in einem Wörterbuch jeweils auf den Datensatz abbilden. Die sind hoffentlich eindeutig?

Und dann liest man die andere Datei ein und hat ja bereits das Wörterbuch mit dem man eine E-Mail-Adresse auf den dazugehörigen Datensatz der anderen Datei abbilden kann.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
mapo
User
Beiträge: 6
Registriert: Montag 1. November 2021, 14:14

__blackjack__ hat geschrieben: Dienstag 2. November 2021, 13:28 @mapo: Der Code ist wenig übersichtlich geschrieben. Da solltest Du dran arbeiten. Zum Beispiel nicht eine Datei öffnen, einen csv-Reader erstellen und dann über die Hälfte der Programmzeilen die gar nichts damit machen, und dann erst der Code der das tatsächlich benutzt.

Bei der einen Datei verwendest Du ``with``, bei der anderen nicht. Warum? Die wird nicht sauber geschlossen. Nicht einmal mit einem manuellen `close()`.

Beim lesen von ``TestdatenO.csv`` wird am Ende ausschlieslich der letzte Eintrag in `kontakte` eingetragen, weil das *hinter* der Schleife steht und nicht im Schleifenkörper. Falls die Datei ausser der Kopfzeile leer ist, führt das zudem zu einer Ausnahme weil `eintrag` dann undefiniert ist. Ich vermute mal das sollte *in* die Schleife.

Dann lassen sich da benannte Zwischenergebnisse einfach einsetzen, und dann kann man aus der Schleife eine einfache „dict comprehension“ machen.

Beim Verarbeiten von ``MAListeV.csv`` ist wieder das gleiche Problem: Du prüfst *nach* der Schleife etwas mit dem letzten Datensatz aus der Datei was wohl für *jeden* Datensatz geprüft werden sollte. Und Du tust das mit einer Schleifenvariablen aus der Verarbeitung der vorhergehenden Datei, also auch wieder nur mit dem letzten Datensatz und den Namen `zeile` gibt es da auch nur falls die Schleife der ersten Datei tatsächlich mindestens einmal durchlaufen wurde. Sonst gibt es eine Ausnahme weil der Name nicht definiert ist.

Der Test mit ``in`` ist ziemlich sicher falsch, denn Du willst ja nicht wissen ob eine E-Mail *in* einer anderen enthalten ist, sondern ob die *gleich* sind. E-Mail-Adressen können auch in anderen E-Mail-Adressen enthalten sein und unterschiedlich sein.

Nicht funktionierender Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import json


def main():
    with open(
        "TestdatenO.csv", "r", newline="", encoding="utf-8"
    ) as csv_datei:
        dialect = csv.Sniffer().sniff(csv_datei.readline())
        csv_datei.seek(0)
        reader = csv.reader(csv_datei, dialect)
        kopfzeile = next(reader)
        kontakte = {
            f" {zeile[1]}": {kopfzeile[1]: zeile[1]} for zeile in reader
        }

    print(json.dumps(kontakte, indent=4))

    with open("MAListeV.csv", "r", newline="", encoding="utf-8") as file:
        daten_csv = csv.DictReader(file, delimiter=",")
        for row in daten_csv:
            print(row["Email"])
            #
            # FIXME `zeile` gibt es hier nicht, und es würde auch keinen Sinn
            # machen sich hier auf eine *möglicherweise* existierende
            # Laufvariable aus einer vorher bereits beendeten Schleife zu
            # beziehen.
            # 
            if zeile[1] == row["Email"]:
                print("Funktioniert")


if __name__ == "__main__":
    main()
Eine doppelt verschachtelte Schleife würde wahrscheinlich funktionieren, hätte aber ein gruseliges Laufzeitverhalten. Man würde erst eine der Dateien einlesen und dort die E-Mail-Adresse(n) in einem Wörterbuch jeweils auf den Datensatz abbilden. Die sind hoffentlich eindeutig?

Und dann liest man die andere Datei ein und hat ja bereits das Wörterbuch mit dem man eine E-Mail-Adresse auf den dazugehörigen Datensatz der anderen Datei abbilden kann.
Danke erstmal für die Antwort. Das vieles noch nicht ordentlich bzw. schlecht ist, liegt ganz einfach daran, dass ich erst vor 3 Tagen mit Python angefangen habe: Sorry schonmal dafür :) Wenn ich die "TestdatenO" einlese, wie du es Vorgeschlagen hast, passiert bei mir rein gar nicht. Ich weiß nicht ob ich da auf dem Schlauche stehe oder nicht, aber vorher hat das zumindest funktioniert. Ansonst werde ich jetzt erstmal noch etwas rumtüffteln müssen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte nicht den gesamten Post davor zitieren. Der steht da schon.
Antworten