Vergleich von zwei Files

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
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Hallo zusammen

Ich versuche die ersten Zeichen in zwei Files auf Gleichheit zu überprüfen. Die Files sehen so aus:
  • setup keywords 1
    Title1
    comment1
    N( 1 PRO* 1) 0.01245965 +1 0.07673554 +1 -0.05772082 +1 -0.4053
    C( 2 PRO* 1) 1.50693114 +1 0.02121969 +1 -0.01874981 +1 -0.1167
    C( 3 PRO* 1) 2.10882265 +1 1.42991342 +1 -0.05147952 +1 0.5845
    [...]
und genau so für das zweite File.

Mein Code sieht nun so aus:

Code: Alles auswählen

#!/usr/bin/env python
import os, sys 

file1 = open(sys.argv[1])
file2 = open(sys.argv[2])

data1 = file1.readlines()
data2 = file2.readlines()

control = map(lambda x, y: x.split()[0] == y.split()[0], data1[:-1], data2[:-1])
Dh. der Witz ist, dass ich so kontrollieren kann, das in beiden Files die Elemente in der gleichen Reihenfolge stehen.
Eine Frage nun: angenommen eine Zeile ist leer, dann crashed meine lambda Funktion. Wie kann ich das abfangen? data1[:-1] ist notwendig, weil eben die letzte Zeile gerade leer ist.
[url=http://www.proandkon.com]proandkon.com[/url]
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Anhand der `#!`-Zeile in einem Python-Programm schließe ich, dass du etwas unix-artiges als Betriebssystem nutzt. Warum benutzt du da nicht einfach `diff`? Und dreht sich http://python-forum.de/viewtopic.php?f=11&t=22856 nicht um die selbe Frage?

Hier ein Schnellschuss von mir. Da sich zip() nicht so verhielt, wie ich dachte, habe ich einfach meine eigene Version davon geschrieben, die allerdings recht umständlich aussieht.

Code: Alles auswählen

with open("/tmp/a") as a, open("/tmp/b") as b:
    def zip(x, y):
        x = iter(x)
        y = iter(y)
        while True:
            xe, ye = False, False
            try:
                xx = next(x)
            except:
                xx = "\n"
                xe = True
            try:
                yy = next(y)
            except:
                yy = "\n"
                ye = True
            if xe and ye:
                break
            yield xx, yy
    
    line = 0
    for la, lb in zip(a, b):
        line += 1
        if la != lb:
            print("Unterschied in %s:" % line)
            print(repr(la))
            print(repr(lb))
            break
    else:
        print("alles gleich")
Stefan
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@sma: ich glaube du suchst itertools.izip_longest.
Das Leben ist wie ein Tennisball.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Exakt. Ich wusste doch, das geht besser:

Code: Alles auswählen

with open("/tmp/a") as a, open("/tmp/b") as b:
    from itertools import zip_longest
    line = 0
    for la, lb in zip_longest(a, b, fillvalue="\n"):
        line += 1
        if la != lb:
            print("Unterschied in %s:" % line)
            print(repr(la))
            print(repr(lb))
            break
    else:
        print("alles gleich")
Stefan
BlackJack

Ich würde ja noch das manuelle hochzählen von `line` durch `enumerate()` ersetzen.

Code: Alles auswählen

with open("/tmp/a") as a, open("/tmp/b") as b:
    from itertools import count, zip_longest
    for line, (la, lb) in enumerate(zip_longest(a, b, fillvalue="\n")):
        if la != lb:
            print("Unterschied in %s:" % (line + 1))
            print(repr(la))
            print(repr(lb))
            break
    else:
        print("alles gleich")
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

danke für die hinweise.
Ja, das ist dasselbe wie ich schon mal gepostet habe. Wollte einfach meine neuste Lösung präsentieren.

Muss mir die Vorschläge aber zuerst genau anschauen. Auf den ersten Blick sehe ich aber nicht, wieso mein Vorschlag nicht auch berechtigt sein soll.

So wie ich das verstehe ich difflib dann empfehlenswert, wenn z.B "Hochwasser" und "Hohcwaser" als ähnlich erkannt werden sollten. Bei mir findet aber keine User-Eingabe statt und somit sind die Fehlermöglichkeiten wirklich nur auf ein Zeichen eingeschränkt.

Und überhaupt, ich bin eigentlich nur schon froh, dass ich mal eine Situation mit lambda und map() angehen konnte ;)
[url=http://www.proandkon.com]proandkon.com[/url]
Benutzeravatar
noisefloor
User
Beiträge: 4208
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

folgende Lösung passt IMHO aber auch:

Code: Alles auswählen

datei1 = open('file1','r')
datei2 = open('file2','r')

comp1 = [a[0] for a in datei1 if a.strip()]
comp2 = [b[0] for b in datei2 if b.strip()]

if comp1 == comp2:
    print "Stimmt"
else:
    print "Stimmt nicht"
Gruß, noisefloor
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

noisefloor, die Lösung funktioniert, solange die Datein ziemlich klein sind, sobald sie größer sind, gibts nen MemoryError
the more they change the more they stay the same
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

noisefloor hat geschrieben:folgende Lösung passt IMHO aber auch:
Nein ;)
* Es fehlt ein `try..finally` bzw. `with`.
* Du überprüfst nur jeweils das erste Zeichen jeder Zeile.
* Diese Lösung ist DEUTLICH speicherhungriger und unperformanter.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Benutzeravatar
noisefloor
User
Beiträge: 4208
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

ms4py hat geschrieben: * Es fehlt ein `try..finally` bzw. `with`
Stimmt. Ist mir hinterher eingefallen. Bzw. das zumindest `close` fehlt . ;-)
ms4py hat geschrieben:Du überprüfst nur jeweils das erste Zeichen jeder Zeile.
Ja, natürlich. Weil: Im 1. Posting steht "Ich versuche die ersten Zeichen in zwei Files auf Gleichheit zu überprüfen." :-)
ms4py hat geschrieben: Diese Lösung ist DEUTLICH speicherhungriger und unperformanter.
Dafür einfacher zu verstehen. ;-)

Im Ernst: Wieso? Der Code braucht keinen Import-Statement, List Comprehension ist AFAIK ziemlich performant -> also woran liegst?

Gruß, noisefloor
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.
noisefloor hat geschrieben:Stimmt. Ist mir hinterher eingefallen. Bzw. das zumindest `close` fehlt . ;-)
Der Hinweis auf try-finally, bzw with war schon angebracht. Wenn du zum Beispiel die erste Datei öffnest aber das Öffnen der zweiten fehlschlägt, dann wirst du dein close niemals erreichen.
noisefloor hat geschrieben:Im Ernst: Wieso? Der Code braucht keinen Import-Statement, List Comprehension ist AFAIK ziemlich performant -> also woran liegst?
Das Problem liegt darin, dass du alle Daten auf einmal mittels der LC einliest und diese gleichzeitig gehalten werden müssen. sma hingegen liest nur die Zeilen ein, die gerade verglichen werden sollen. Wenn zwei Zeilen sich unterscheiden, hört die Verarbeitung sofort auf.

Sebastian
Das Leben ist wie ein Tennisball.
Benutzeravatar
noisefloor
User
Beiträge: 4208
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

ok, verstehe. Es geht also nicht um die Laufzeit, sondern das, was im Speicher gehalten wird. So weit verstanden.

Andere Frage:
War die Anforderung ans Programm, dass Leerzeilen nicht als Unterschied gelten oder doch?

Also sollen z.B.

Code: Alles auswählen

foo
bar
spam
egg
und

Code: Alles auswählen

foo
bar 

spam
egg
gleich sein oder nicht? Für sma's Variante ist es ein Unterschied, für meine nicht. :-)

Gruß, noisefloor
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Hallo, danke für die Beiträge.

Zum letzten Post von noisefloor, Leerzeilen werden nicht vorkommen, weil das Datenformat diese nicht vorsieht (im Block mit den Koordinaten). Allerdings kommen evtl. am Anfang eine oder zwei Leerzeilen vor, wenn ein User keinen Titel setzt und keine Beschreibung angibt.
Was mich interessieren würde ist, wie ich diese Leerzeilen mit dem Code den ich gepostet habe, abfangen könnte, weil bei mir crashed das jeweils. Und ja, es geht eigentlich nur um das erste Zeichen bzw. String, weil dort das Element angegeben wird ('H', 'O', 'Cl', etc).
[url=http://www.proandkon.com]proandkon.com[/url]
BlackJack

@mzh: Du sagst immer das "crashed", was es aber sicher nicht tut. Es wird eine Ausnahme geben und die sollte Dir eigentlich sagen was da passiert. Falls nicht, probier die Operationen doch einfach mal Stück für Stück interaktiv auf einer leeren Zeichenkette. Spätestens dann sollte klar sein was passiert und damit auch was man dagegen tun kann.
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/mzh/shellscripts/comp.py", line 21, in ?
    control = map(lambda x, y: x.split()[0] == y.split()[0], data1[:-1], data2[:-1])
  File "/home/mzh/shellscripts/comp.py", line 21, in <lambda>
    control = map(lambda x, y: x.split()[0] == y.split()[0], data1[:-1], data2[:-1])
IndexError: list index out of range
ja, ich krieg schon mit, dass da ein IndexError auftritt, weil die Liste wohl leer sein wird, da es ja keine Zeichen auf einer leeren Zeile gibt. Es ist nicht split(), das scheitert, sondern split()[0] und ich weiss bis jetzt nicht, wie ich eine leere Zeile berücksichtigen kann (ich kann ja kein if statement in lambda einbauen oder doch?).
@BlackJack: hier ist es also notwendig, den IndexError abzufangen. Mein Ziel ist es jedenfalls, das ganze ohne for-loop zu erledigen.
[url=http://www.proandkon.com]proandkon.com[/url]
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

mzh hat geschrieben:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/mzh/shellscripts/comp.py", line 21, in ?
    control = map(lambda x, y: x.split()[0] == y.split()[0], data1[:-1], data2[:-1])
  File "/home/mzh/shellscripts/comp.py", line 21, in <lambda>
    control = map(lambda x, y: x.split()[0] == y.split()[0], data1[:-1], data2[:-1])
IndexError: list index out of range
ja, ich krieg schon mit, dass da ein IndexError auftritt, weil die Liste wohl leer sein wird, da es ja keine Zeichen auf einer leeren Zeile gibt. Es ist nicht split(), das scheitert, sondern split()[0] und ich weiss bis jetzt nicht, wie ich eine leere Zeile berücksichtigen kann (ich kann ja kein if statement in lambda einbauen oder doch?).
@BlackJack: hier ist es also notwendig, den IndexError abzufangen. Mein Ziel ist es jedenfalls, das ganze ohne for-loop zu erledigen.
Mal [:1] statt [0] versuchen?
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Danke, das ist sehr hilfreich.
[url=http://www.proandkon.com]proandkon.com[/url]
BlackJack

@mzh: Ansonsten muss man das ja auch nicht mit aller Gewalt in eine ``lambda``-Funktion quetschen wollen. In einer mit ``def`` definierten Funktion kann man mehr machen, zum Beispiel den Sonderfall mit einem ``if`` behandeln.
Benutzeravatar
noisefloor
User
Beiträge: 4208
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die potentiellen Leerzeilen war ja auch das, was mich zu meinem Codebewegt hat. Da werden diese nämlich gekonnt ignoriert. :-) . Na gut, Nachteile -> siehe oben. ;-)

Gruß, noisefloor
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

BlackJack hat geschrieben:@mzh: Ansonsten muss man das ja auch nicht mit aller Gewalt in eine ``lambda``-Funktion quetschen wollen. In einer mit ``def`` definierten Funktion kann man mehr machen, zum Beispiel den Sonderfall mit einem ``if`` behandeln.
Natürlich, da stimme ich voll zu... für mich ist es einfach eine gute Gelegenheit, die verschiedenen Sprachelemente von Python ein bisschen besser kennen zu lernen. Das war die Motivation für mich, das so zu versuchen.

@noisefloor: soweit ich das sehe, löst der Vorschlag von bords0 das Problem mit den Leerzeilen ebenfalls recht einfach
[url=http://www.proandkon.com]proandkon.com[/url]
Antworten