Textdatei in LinkedList einlesen

Anfängerfragen zum Programmieren mit PureBasic.
matbal
Beiträge: 261
Registriert: 30.03.2011 20:53

Re: Textdatei in LinkedList einlesen

Beitrag 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 
Zuletzt geändert von matbal am 24.04.2013 01:07, insgesamt 1-mal geändert.
Martin66119
Beiträge: 282
Registriert: 03.01.2005 11:36

Re: Textdatei in LinkedList einlesen

Beitrag 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.
Benutzeravatar
helpy
Beiträge: 636
Registriert: 29.08.2004 13:29

Re: Textdatei in LinkedList einlesen

Beitrag 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!
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Martin66119
Beiträge: 282
Registriert: 03.01.2005 11:36

Re: Textdatei in LinkedList einlesen

Beitrag von Martin66119 »

Und was muss ich machen, damit alles im korrekten Format ist.
Martin66119
Beiträge: 282
Registriert: 03.01.2005 11:36

Re: Textdatei in LinkedList einlesen

Beitrag von Martin66119 »

In den Compiler-Options ist "create unicode executabe" nicht markiert. Es sollte also passen
Benutzeravatar
helpy
Beiträge: 636
Registriert: 29.08.2004 13:29

Re: Textdatei in LinkedList einlesen

Beitrag 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!
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Martin66119
Beiträge: 282
Registriert: 03.01.2005 11:36

Re: Textdatei in LinkedList einlesen

Beitrag von Martin66119 »

Hast du einen Vorschlag, wie man den code um die ein oder ander Zeile reduzieren kann und auch etwas beschleunigen?
Benutzeravatar
helpy
Beiträge: 636
Registriert: 29.08.2004 13:29

Re: Textdatei in LinkedList einlesen

Beitrag 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
Windows 10
PB Last Final / (Sometimes testing Beta versions)
matbal
Beiträge: 261
Registriert: 30.03.2011 20:53

Re: Textdatei in LinkedList einlesen

Beitrag 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.
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Textdatei in LinkedList einlesen

Beitrag 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).
Antworten