Zwei Linked Lists vergleichen

Anfängerfragen zum Programmieren mit PureBasic.
Demivec
Beiträge: 49
Registriert: 22.02.2008 20:49
Wohnort: Utah, USA

Re: Zwei Linked Lists vergleichen

Beitrag von Demivec »

Besser:

Code: Alles auswählen

ForEach Dest()
  ;If source()\relativepath + source()\name = Dest()\relativepath + Dest()\name
  If source()\name = Dest()\name And source()\relativepath = Dest()\relativepath
    DeleteElement(Dest())
    FoundEntry = #True
    Break
  EndIf
Next
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Zwei Linked Lists vergleichen

Beitrag von NicTheQuick »

Noch besser:

Code: Alles auswählen

ForEach Dest()
  ;If source()\relativepath + source()\name = Dest()\relativepath + Dest()\name
  If CompareMemoryString(@source()\name, @Dest()\name, #PB_String_NoCase) = #PB_String_Equal And CompareMemoryString(@source()\relativepath, @Dest()\relativepath, #PB_String_NoCase) = #PB_String_Equal
    DeleteElement(Dest())
    FoundEntry = #True
    Break
  EndIf
Next 
Warum ich '#PB_String_NoCase' nutze kann man aus meinem letzten Post erschließen.
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Zwei Linked Lists vergleichen

Beitrag von Kiffi »

der Vollständigkeit halber hier nochmal eine einfache datenbankbasierte Lösung:

Code: Alles auswählen

Structure sFile
  Path.s
  Name.s
EndStructure

NewList SourceFile.sFile()
NewList DestinationFile.sFile()

Procedure ListFiles(EntryPath.s, List File.sFile())
  
  ; by Lebostein
  ; http://www.purebasic.fr/german/viewtopic.php?p=80742#p80742
  
  Protected UsedDirectory
  Protected EntryType
  Protected EntryName.s
  
  If Right(EntryPath, 1) <> "\" : EntryPath + "\" : EndIf
  
  UsedDirectory = ExamineDirectory(#PB_Any, EntryPath, "*.*")
  
  If UsedDirectory
    
    While NextDirectoryEntry(UsedDirectory)
      
      EntryType = DirectoryEntryType(UsedDirectory)
      EntryName = DirectoryEntryName(UsedDirectory)
      
      If EntryName = "." Or EntryName = "..": Continue: EndIf
      
      If EntryType = #PB_DirectoryEntry_File
        AddElement(File())
        File()\Path = EntryPath
        File()\Name = EntryName
      EndIf
      
      If EntryType = #PB_DirectoryEntry_Directory: ListFiles(EntryPath + EntryName, File()): EndIf
      
    Wend
    
    FinishDirectory(UsedDirectory)
    
  EndIf
  
EndProcedure

ClearList(SourceFile())
ClearList(DestinationFile())

ListFiles("D:\test\tango1\", SourceFile())
ListFiles("D:\test\tango2\", DestinationFile())

UseSQLiteDatabase()

DB = OpenDatabase(#PB_Any, ":memory:", "", "", #PB_Database_SQLite)

DatabaseUpdate(DB, "Create Table SourceFiles (Path, Name)")
DatabaseUpdate(DB, "Create Table DestinationFiles (Path, Name)")

ForEach SourceFile()
  DatabaseUpdate(DB, "Insert Into SourceFiles (Path, Name) Values ('" + SourceFile()\Path + "', '" + SourceFile()\Name + "')")
Next

ForEach DestinationFile()
  DatabaseUpdate(DB, "Insert Into DestinationFiles (Path, Name) Values ('" + DestinationFile()\Path + "', '" + DestinationFile()\Name + "')")
Next

Debug "Dateien, die in Source fehlen:"
If DatabaseQuery(DB, "Select Name From DestinationFiles Where Name Not In (Select Name From SourceFiles)")
  While NextDatabaseRow(DB)
    Debug GetDatabaseString(DB, 0)
  Wend
  FinishDatabaseQuery(DB)
EndIf

Debug "Dateien, die in Destination fehlen:"
If DatabaseQuery(DB, "Select Name From SourceFiles Where Name Not In (Select Name From DestinationFiles)")
  While NextDatabaseRow(DB)
    Debug GetDatabaseString(DB, 0)
  Wend
  FinishDatabaseQuery(DB)
EndIf

CloseDatabase(DB)
Habe jetzt keine Geschwindigkeitsmessung gemacht, dürfte aber recht flott sein.

Grüße ... Kiffi

// Edit: Die LinkedLists braucht man hier eigentlich nicht

Code: Alles auswählen

Procedure ListFiles(EntryPath.s, DB, Tablename.s)
  
  ; by Lebostein
  ; http://www.purebasic.fr/german/viewtopic.php?p=80742#p80742
  
  Protected UsedDirectory
  Protected EntryType
  Protected EntryName.s
  
  If Right(EntryPath, 1) <> "\" : EntryPath + "\" : EndIf
  
  UsedDirectory = ExamineDirectory(#PB_Any, EntryPath, "*.*")
  
  If UsedDirectory
    
    While NextDirectoryEntry(UsedDirectory)
      
      EntryType = DirectoryEntryType(UsedDirectory)
      EntryName = DirectoryEntryName(UsedDirectory)
      
      If EntryName = "." Or EntryName = "..": Continue: EndIf
      
      If EntryType = #PB_DirectoryEntry_File
        
        DatabaseUpdate(DB, "Insert Into " + Tablename + " (Path, Name) Values ('" + EntryPath + "', '" + EntryName + "')")
        
      EndIf
      
      If EntryType = #PB_DirectoryEntry_Directory: ListFiles(EntryPath + EntryName, DB, Tablename): EndIf
      
    Wend
    
    FinishDirectory(UsedDirectory)
    
  EndIf
  
EndProcedure

UseSQLiteDatabase()

DB = OpenDatabase(#PB_Any, ":memory:", "", "", #PB_Database_SQLite)

DatabaseUpdate(DB, "Create Table SourceFiles (Path, Name)")
DatabaseUpdate(DB, "Create Table DestinationFiles (Path, Name)")

ListFiles("D:\test\tango1\", DB, "SourceFiles")
ListFiles("D:\test\tango2\", DB, "DestinationFiles")

Debug "Dateien, die in Source fehlen:"
If DatabaseQuery(DB, "Select Name From DestinationFiles Where Name Not In (Select Name From SourceFiles)")
  While NextDatabaseRow(DB)
    Debug GetDatabaseString(DB, 0)
  Wend
  FinishDatabaseQuery(DB)
EndIf

Debug "Dateien, die in Destination fehlen:"
If DatabaseQuery(DB, "Select Name From SourceFiles Where Name Not In (Select Name From DestinationFiles)")
  While NextDatabaseRow(DB)
    Debug GetDatabaseString(DB, 0)
  Wend
  FinishDatabaseQuery(DB)
EndIf

CloseDatabase(DB)
a²+b²=mc²
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

Re: Zwei Linked Lists vergleichen

Beitrag von Makke »

Vielen Dank für die weiteren Tips.

@Demivec: das habe ich nun so geändert:

Code: Alles auswählen

    ForEach Dest()
      If Source()\relativepath = Dest()\relativepath
        If Source()\name = Dest()\name
          DeleteElement(Dest())
          FoundEntry = #True
          Break
        EndIf
      EndIf
    Next
Damit ist die Schleife nochmals deutlich schneller geworden. Ich merke mir also für die Zukunft wenn möglich auf Strings verzichten.

@NicTheQuick: Die Strings im Speicher zu vergleichen geht, ich frage mich nur warum, laut Beschreibung müssen die Strings Null-terminiert sein, wenn man keine Länge angibt. Aber warum sind die gespeicherten Strings anscheinend terminiert ? Ist das bei PB so, dass die String-Variablen immer terminiert sind ?

Und jetzt noch eine Frage, wenn ich das Programm starte, wird das Fenster nicht komplett aufgebaut, siehe hier:

Bild

Warum ist das so ? Immerhin wird der Code für das Fenster ja eigentlich komplett ausgeführt und dann werden erst die Verzeicnisse durchsucht.
---
Windows 11 (64 bit)
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Zwei Linked Lists vergleichen

Beitrag von Kiffi »

Makke hat geschrieben:Warum ist das so ? Immerhin wird der Code für das Fenster ja eigentlich komplett ausgeführt und dann werden erst die Verzeicnisse durchsucht.
Deine Event-Schleife muss aber immer laufen (nicht nur einmal), um
die GUI korrekt zu zeichnen. Abhilfe bringt hier, Deinen Code für das Suchen
und Vergleichen in einen Thread auszulagern, der dann parallel zu Deiner
Eventschleife läuft.

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Zwei Linked Lists vergleichen

Beitrag von STARGÅTE »

Hier mal ein Beispiel:

Code: Alles auswählen

Enumeration
	#Window
	#ProgressBarGadget
	#TextGadget
EndEnumeration

Procedure Load(Null=#Null)
	Protected Index
	For Index = 0 To 100
		SetGadgetText(#TextGadget, Str(Random($7FFFFFFF)))
		SetGadgetState(#ProgressBarGadget, Index)
		Delay(Random(300))
	Next
EndProcedure

OpenWindow(#Window, 0, 0, 400, 60, "WindowTitle", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
	TextGadget(#TextGadget, 10, 10, 380, 20, "")
	ProgressBarGadget(#ProgressBarGadget, 10, 30, 380, 20, 0, 100)

CreateThread(@Load(), #Null)

Repeat
	
	Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			End
	EndSelect
	
ForEver
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Zwei Linked Lists vergleichen

Beitrag von Kiffi »

STARGÅTE hat geschrieben:Hier mal ein Beispiel:
AFAIK sollte man vermeiden, aus einem Thread heraus direkt
auf die GUI (=anderer Thread) zuzugreifen, weil es sonst zu
schwer nachvollziehbaren IMAs kommen kann.

Aus diesem Grund arbeite ich mit SendMessage_().

Code: Alles auswählen

Enumeration
  #Window
  #ProgressBarGadget
  #TextGadget
EndEnumeration

#RedrawProgressBar = #WM_USER

Procedure Load(Null=#Null)
  Protected Index
  For Index = 0 To 100
    PostMessage_(WindowID(#Window), #RedrawProgressBar, Index, 0)
    Delay(Random(300))
  Next
EndProcedure

OpenWindow(#Window, 0, 0, 400, 60, "WindowTitle", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ProgressBarGadget(#ProgressBarGadget, 10, 30, 380, 20, 0, 100)

CreateThread(@Load(), #Null)

Repeat
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow
      End
      
    Case #RedrawProgressBar
      SetGadgetState(#ProgressBarGadget, EventwParam())
      
  EndSelect
  
ForEver
Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: Zwei Linked Lists vergleichen

Beitrag von PMV »

Ich dachte, SetGadgetXXX macht genau das unter Windows?
Aber selbst wenn nicht, nur das erstellen von Fensterelementen muss
im selben Thread passieren, wo sich der Event-Loop befindet.
Zugriffe und Veränderungen können in anderen Thread ausgeführt
werden.

da: http://www.purebasic.fr/german/viewtopi ... 18&start=0
(zu freaks post scrollen)

Das ist zumindest mein Stand. Hast du da andere Erfahrungen?
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Zwei Linked Lists vergleichen

Beitrag von STARGÅTE »

@Kiffi:

Meines Wissens nach sind die Set/Get befehle der Gadgets (inzwischen) Threadsicher.
Und laut Freak:
[...]Also sollten der Thread der das Fenster/Gadget erzeugt hat einen laufenden Eventloop haben,
dann ist Manipulation der Gadgets von anderen Threads kein Problem.
Das einzige was man beachten sollte ist nur, dass mann sichergehen muss, dass das Gadget auch existiert bzw. bereit ist für eine Veränderung ist, wie also Freak schrieb, irgendwo ein WindowEvent aufgerufen werden muss.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Zwei Linked Lists vergleichen

Beitrag von NicTheQuick »

Makke hat geschrieben:@NicTheQuick: Die Strings im Speicher zu vergleichen geht, ich frage mich nur warum, laut Beschreibung müssen die Strings Null-terminiert sein, wenn man keine Länge angibt. Aber warum sind die gespeicherten Strings anscheinend terminiert ? Ist das bei PB so, dass die String-Variablen immer terminiert sind ?
PB-Strings sind immer Nullterminiert. Bei Windows selbst sind Strings im Normalfall übrigens auch Nullterminiert.

Mir ist grad noch was eingefallen. Wozu haben wir eigentlich die Maps in Purebasic? Damit wäre es ja ein leichtes herauszufinden ob eine Datei aus 'Dest' schon in 'Source' existiert. Also als Key einfach den Dateinamen inklusive relativen Pfad nehmen und dann durch Dest laufen und immer schauen, ob das ganze schon in Source ist. Es wäre mal ein Versuch Wert zu testen, ob das schneller als meine Lösung ist. Aber ich hab dafür gerade keine Zeit. :wink:
Antworten