Seite 2 von 2

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 15:08
von matbal
Das Abgleichen der beiden Dateien läßt sich sehr simpel gestalten, wenn man die Zeilen in beiden Listen vorher sortiert. Dann braucht man beim Vergleichen beide Listen nur ein einziges Mal durchgehen.

Falls die Reihenfolge der Zeilen wichtig ist, muß man sich beim Einlesen auch die Zeilennummer merken. Nach dem Vergleich kann man dann wieder nach Zeilennummer sortieren...

(Ich habe es mit PB 5.0 geschrieben. in PB 5.1 müssen die Konstanten für SortStructuredList() angepaßt werden, weil sie sich geändert haben)

Code: Alles auswählen

Structure ZeileStruc
   Text$    ; Zeileninhalt
   n.i      ; Zeilennummer
EndStructure

Procedure LoadFile(File$, List Text.ZeileStruc())
   Protected n
   
   If ReadFile(0, File$)
      While Not Eof(0)
         AddElement(Text())
         With Text()
            \Text$ = ReadString(0)
            \n = n
            n + 1
         EndWith
      Wend
      CloseFile(0)
   EndIf
   
   ProcedureReturn n
   
EndProcedure

Procedure CompareText(List Text1.ZeileStruc(), List Text2.ZeileStruc())
   ; Beide Texte sortieren
   SortStructuredList(Text1(), #PB_Sort_Ascending, OffsetOf(ZeileStruc\Text$), #PB_Sort_String)
   SortStructuredList(Text2(), #PB_Sort_Ascending, OffsetOf(ZeileStruc\Text$), #PB_Sort_String)
   
   ; In beiden Dateien zeilen weise einmal von oben nach
   ; unten durchgehen und vergleichen
   
   Protected e1 = FirstElement(Text1())   
   Protected e2 = FirstElement(Text2())   
   
   Repeat
      If Text1()\Text$ < Text2()\Text$
         If e1 : e1 = NextElement(Text1()) : EndIf
         
      ElseIf Text1()\Text$ > Text2()\Text$
         If e2 : e2 = NextElement(Text2()) : EndIf
         
      ElseIf Text1()\Text$ = Text2()\Text$
         DeleteElement(Text1())
         DeleteElement(Text2())
         If e1 : e1 = NextElement(Text1()) : EndIf
         If e2 : e2 = NextElement(Text2()) : EndIf
         
      EndIf
   Until e1 = 0 Or e2 = 0
   
   ; Sortierung rückgängig machen
   SortStructuredList(Text1(), #PB_Sort_Ascending, OffsetOf(ZeileStruc\n), #PB_Sort_Integer)
   SortStructuredList(Text2(), #PB_Sort_Ascending, OffsetOf(ZeileStruc\n), #PB_Sort_Integer)
   
EndProcedure


NewList Text1.ZeileStruc()
NewList Text2.ZeileStruc()

Define File1$ = "Text1.txt"
Define File2$ = "Text2.txt"

LoadFile(File1$, Text1())
LoadFile(File2$, Text2())
CompareText(Text1(), Text2())

Debug "Nur in Text1 enthalten:"
ForEach Text1()
   Debug Text1()\Text$
Next 

Debug "Nur in Text2 enthalten"
ForEach Text2()
   Debug Text2()\Text$
Next 

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:04
von Martin66119
Hallo,

ich habe eine Lösung hinbekommen. Vermutlich zwar um 7 Ecken aber es geht.

In den beiden Dateien sind ca. 20000 Datensätze. Die Anzahl in beiden Dateien muss nicht gleich sein.
Ich möchte immer die Datei 2 mit der Datei 1 vergleichen und die Daten, die in der Datei 2 aber nicht in der Datei 1 enthalten sind heraussuchen und in einer neuen Datei 3 speichern.


Hier nun meine Lösung:

Code: Alles auswählen

NewList Liste1.s()
NewList Liste2.s()
NewList Liste3.s()
NewList DateiName.s()
Gefunden.b = 0

DeleteFile("Datei3.txt")
ReadFile(1,"datei 1.txt")
While Eof(1)=0
  AddElement(Liste1())
  Liste1()=ReadString(1)
Wend
CloseFile(1)

ReadFile(1,"datei 2.txt")
While Eof(1)=0
  AddElement(Liste2())
  Liste2()=ReadString(1)
Wend
CloseFile(1)

ForEach Liste2()
  ForEach Liste1()
    If Liste2() = Liste1()
      Gefunden = 1
    EndIf
  Next
  If Gefunden = 0
    AddElement(Liste3())
    Liste3() = Liste2()
  EndIf
  Gefunden = 0
Next

  If CreateFile(0, "Datei3.txt")         
    ForEach Liste3()
      WriteStringN(0, Liste3())  
     Next
    CloseFile(0)                       
  Else
    MessageRequester("Information","Konnte Datei nicht erstellen!")
  EndIf

Wenn man den Code verkleinern kann und auch noch beschleunigen, das wäre toll.

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:39
von helpy
Ein Hinweis zum Lesen/Schreiben der Datei:

Du solltest zusätzlich folgendes berücksichtigen:
  • In welchem Format liegt die Textdatei vor (ANSI, UTF8, UTF16, ...)?
  • Wird das Programm im UNICODE Modus kompiliert oder nicht?
In Deinem Programm verhält sich ReadString wie folgt:
Der Text aus der Datei wird als UTF8-String gelesen, wenn das Programm im Unicode-Modus kompiliert wird, andernfalls wird er als ASCII gelesen.
In Deinem Programm verhält sich WriteStringN wie folgt:
Der Text wird als UTF8-String in die Datei geschrieben, wenn das Programm im Unicode-Modus kompiliert wird, andernfalls wird dieser als ASCII geschrieben.
Sollte das verwendete Format nicht mit dem Datei-Format übereinstimmen, dann kann es zu einer fehlerhaften Ausgabe kommen!

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:45
von Martin66119
Und was muss ich machen, damit alles im korrekten Format ist.

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:49
von Martin66119
In den Compiler-Options ist "create unicode executabe" nicht markiert. Es sollte also passen

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:55
von helpy
Martin66119 hat geschrieben:In den Compiler-Options ist "create unicode executabe" nicht markiert. Es sollte also passen
Dann werden die Dateien im ASCII-Format gelesen/geschrieben!
Wenn Deine Dateien in diesem Format vorliegen, dann sollte es gehen!

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 21:59
von Martin66119
Hast du einen Vorschlag, wie man den code um die ein oder ander Zeile reduzieren kann und auch etwas beschleunigen?

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 23:07
von helpy
"Code reduzieren UND beschleunigen" ... das ist nicht möglich ;-)

Um Lesen und Schreiben der Dateien zu beschleunigen musst Du sicher mehr Code schreiben!
Ein paar Tipps dazu hast Du bereits in oben stehenden Beiträgen erhalten.

Auch die Schleife zum Vergleichen musst Du sicher noch überarbeiten.
Wenn es innerhalb einer Datei identische Zeilen gibt, dann wirst Du mit Deiner Methode falsche Ergebnis bekommen.

Angenommen "ZeileX" kommt in Datei1 1x und in Datei2 10x vor.
Dann findest Du mit Deiner Schleife 10 Übereinstimmungen und die neun zusätzlichen Zeilen aus Datei2, werden nicht in Datei2 geschrieben.

Enthalten Datei1 und Datei2 dieselben Inhalte nur in unterschiedlicher Reihenfolge, dann wird Datei3 leer sein.
Willst Du das oder sollen auch die unterschiedlichen Zeilen in Datei3 geschrieben werden?

Gruß,
guido

Re: Textdatei in LinkedList einlesen

Verfasst: 19.04.2013 23:44
von matbal
Du nimmst jetzt jeden Datensatz und suchst ihn in der anderen Liste, mußt also für jeden Datensatz die komplette andere liste durchsuchen.


Wie ich es machen würde, habe ich oben schon beschrieben. Ich würde einfach beide Listen sortieren. Dann brauchst du nur beide Listen parallel von oben nach unten durchsehen.

Du nimmst das erste Element von beider Listen und vergleichst sie. Wenn sie gleich sind, werden sie gelöscht. Im anderen Fall nimmst du aus der Liste mit dem kleineren Element das nächste Element und vergleichst wieder. Das ganze wiederholst du, bis beide Listen durch sind.

(Stell dir das einfach vor, als würdest du zwei Adressbücher vergleichen. Wenn sie beide sortiert sind, brauchst du beide auch nur einmal durchblättern.)

In beiden Listen sind am Ende dann nur noch die Elemente übrig, die in der anderen Liste nicht vorkamen. Du brauchst also nur noch die Liste 2 abspeichern, und hast alles, was nicht in Liste 1 enthalten ist.

Ich habe am Ende des Vergleichs die übriggebliebenen Elemente wieder in die ursprüngliche Reihenfolge gebracht. Das geht nur, wenn für jedes Listenelement Text und Zeilennummer gespeichert wird. (Listenelemente auf eine Struktur, die sowohl den Text als auch die Zeilennummer beinhaltet)

Wenn die Reihenfolge unwichtig ist, reicht eine einfache Liste mit Strings.

Re: Textdatei in LinkedList einlesen

Verfasst: 20.04.2013 09:31
von Nino
matbal hat geschrieben:Wie ich es machen würde, habe ich oben schon beschrieben. Ich würde einfach beide Listen sortieren. Dann brauchst du nur beide Listen parallel von oben nach unten durchsehen.
So würde ich das auch machen, gar keine Frage. Obwohl das Sortieren einen gewissen -- aber eben relativ geringen -- Zusatzaufwand bedeutet, ist die Gesamtlaufzeit so deutlich kürzer (außer vielleicht bei Listen mit ganz wenigen Elementen): O(n²) vs. O(n log n).