Seite 2 von 4

Re: Zwei Linked Lists vergleichen

Verfasst: 19.09.2011 22:46
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

Re: Zwei Linked Lists vergleichen

Verfasst: 19.09.2011 23:42
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.

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 09:35
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)

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 11:30
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.

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 11:46
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

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 15:36
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

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 17:14
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

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 19:10
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?

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 19:38
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.

Re: Zwei Linked Lists vergleichen

Verfasst: 20.09.2011 20:21
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: