Python Anfänger - Dateiinhalt vergleichen

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.
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Hallo.

Ich bin absoluter Python Anfänger und mache gerade meine ersten Schritte.

Ich möchte gerade den Inhalt zweier Textdateien vergleichen und das Ergebnis in eine dritte Datei schreiben. Beide Dateien enthalten in jeder Zeile einen Namen. Eine grosse Datei A mit allen bekannten Namen und eine kleinere Datei B mit neu hinzugekommenen Namen. In die dritte Datei C sollen nun alle neu hinzugekommenen Namen aus B geschrieben werden die in der grossen Datei A noch nicht enthalten sind.

Das bekomme ich noch nicht ganz gebacken. Ich habe folgendes probiert:

Code: Alles auswählen

with open('A') as big, open('B') as small, open('C', 'w') as new:
    new.writelines(line for line in small if line not in set(big))
Das funktioniert aber ganz und gar nicht wie es soll.

Weiss jemand Rat?
BlackJack

@Bluebay: Die Bedingung wird für jede Zeile in `small` ausgeführt. Überleg mal was passiert wenn man `set(big)` mehrmals ausführt, also insbesondere bei jedem mal ausser dem ersten mal.
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Ich bin gerade auf dem Level mit raw_input und print. Deine Frage überfordert mich leider noch komplett.
BlackJack

@Bluebay: Wie bist Du denn dann auf diese Zeile gekommen? Schreib das mal selber, so dass Du auch verstehst was da passiert. Und probiere einfach mal aus was passiert wenn man `set()` zweimal hintereinander auf das selbe Dateiobjekt anwendet, was da jeweils als Ergebnis kommt.
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Ich bin von meinem Python Online Kurs einfach ein wenig abgewichen und will die mir selbst gestellte Aufgabe jetzt umsetzen. Kannst du mir einen Tip geben in welcher Richtung ich suchen / lesen muss? Den Code habe ich aus dem Web und wenn er wie gewünscht funktionieren würde, hätte ich versucht ihn zu verstehen und ihn zu erweitern. So lerne ich meistens ganz gut.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Bluebay hat geschrieben:Den Code habe ich aus dem Web und wenn er wie gewünscht funktionieren würde, hätte ich versucht ihn zu verstehen und ihn zu erweitern.
Nun funktioniert der Code aber nicht und es ist folglich um so wichtiger, dass du ihn verstehst.

Wir sollten uns da jetzt echt mal durcharbeiten. Was macht denn die erste Zeile?
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Die erste Zeile öffnet alle 3 Dateien und weist ihrem Inhalt Variablen zu. C wird beschreibbar geöffnet.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@Bluebay: was meinst Du mit Inhalt?
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Damit meine ich die Zeichen und Zeichenketten in den jeweiligen Dateien.
BlackJack

@Bluebay: Dann stimmt das schon mal nicht, denn in der ersten Zeile wird mit den Bytes in den Dateien noch gar nichts gemacht.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Bluebay hat geschrieben:Damit meine ich die Zeichen und Zeichenketten in den jeweiligen Dateien.
Nicht so ganz. Die Dateien werden zwar geöffnet, aber nicht gelesen.

Gelesen werden sie, wenn die Daten auf dem Dateiobjekt abgerufen werden. Das kann explizit mit einer Schleife passieren (for line in small) oder auch implizit (set(big)).
Benutzeravatar
snafu
User
Beiträge: 6908
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Bluebay
Um mal ein bißchen was vorweg zu nehmen: Dateiobjekte haben einen Positionszeiger. Nach dem Öffnen einer Datei - d.h. nachdem das Dateiobjekt z.B. mittels `open()` erstellt wurde - steht dieser Positionszeiger vor dem ersten Zeichen. Durch jede Aktion, die dazu führt, dass die Datei komplett durchlaufen wird (Schleife über alle Zeilen, Suchen eines Textabschnitts, Verwendung des Dateiobjekts mit `set()`, `list()`, `tuple()`, ...), steht dieser Zeiger am Ende der Aktion auf der Position hinter dem letzten Zeichen - und dort verbleibt er. Die Konsequenz daraus ist, dass jeder weitere `set()`-Aufruf in deinem Code bei seiner "Abfrage" gegenüber dem Dateiobjekt keine weiteren Zeichen mehr erhält, da der Postionszeiger eben vor keinem weiteren Zeichen mehr steht und somit nichts weiteres ausgeliefert werden kann. Weitere `set`-Objekte werden folglich *immer* leer bleiben. Dies ist sicherlich nicht das Verhalten, welches du bzw der Ersteller deines Codes im Sinn hatten.
BlackJack

Oder mal in einer Python-Shell demonstriert:

Code: Alles auswählen

In [41]: !cat test.txt
one
two
three

In [42]: f = open('test.txt')

In [43]: set(f)
Out[43]: {'one\n', 'three\n', 'two\n'}

In [44]: set(f)
Out[44]: set()

In [45]: set(f)
Out[45]: set()

In [46]: f.close()
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

Ist ja viel Overhead. :)

In der Bash löse ich es einfach mit

Code: Alles auswählen

$ grep -vf A B > C
Ich dachte das es in Python eine ähnlich simple Variante gäbe.
BlackJack

@Bluebay: Ein fertiges Programm benutzen ist einfacher als so ein Programm selber zu schreiben. Wer hätte das gedacht. :roll:

Wieso sollte das in einer allgemeinen Programmiersprache, mit der man so ziemlich alles machen kann, ”simpler” sein als mit einem auf diesen Anwendungsfall spezialisierten Programm? Zumal das semantisch nicht äquivalent ist, denn in A stehen reguläre Ausdrücke wo es Zeichen mit besonderer Bedeutung gibt.
Bluebay
User
Beiträge: 7
Registriert: Montag 14. April 2014, 20:07

BlackJack hat geschrieben:@Bluebay: Ein fertiges Programm benutzen ist einfacher als so ein Programm selber zu schreiben. Wer hätte das gedacht. :roll:
Ja da hast du recht. War nicht unbedingt schlau der Post. Kann mir vielleicht jemand den richtigen Code posten, damit ich mich damit auseinandersetzen kann?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Bluebay hat geschrieben: Kann mir vielleicht jemand den richtigen Code posten, damit ich mich damit auseinandersetzen kann?
Wie wäre es, wenn Du den selber *entwickelst*; besser kann man sich mit einem Problem nicht auseinander setzen! :-) (Und ja, Hilfe dazu gibt es hier - fertige Lösungen eher seltener...)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hier mal ein Ansatz in Clojure (ohne Laden aus Dateien!):

Code: Alles auswählen

user=> (use 'clojure.set)
nil
user=> (def large #{"John Schnee" "Margaery Tyrell" "Robb Stark"})
#'user/large
user=> (def small #{"Tyrion Lannister" "John Schnee"})
#'user/small
user=> (difference small large)
#{"Tyrion Lannister"}
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

C++ mit dem neuen `unordered_set` und laden aus Dateien:

Code: Alles auswählen

#include <fstream>
#include <string>
#include <unordered_set>

using namespace std;

int main()
{
    string line;
    
    ifstream big_file("A");
    unordered_set<string> big;
    while (getline(big_file, line)) {
        big.insert(line);
    }
    big_file.close();

    ifstream small_file("B");
    ofstream out_file("C");
    while (getline(small_file, line)) {
        if (big.find(line) == big.end()) {
            out_file << line << endl;
        }
    }
    out_file.close();
    small_file.close();

    return 0;
}
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Noch einmal Clojure mit dem Lesen aus Dateien:

Code: Alles auswählen

John Schnee
Margaery Tyrell
Rob Starck

Code: Alles auswählen

John Schnee
Tyrion Lannister

Code: Alles auswählen

(use 'clojure.set)
(use '[clojure.string :only (split)])
(def small (apply hash-set (split (slurp "small.txt") #"\n")))
(def large (apply hash-set (split (slurp "large.txt") #"\n")))
(println (difference small large))
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten