"Tree"-Variable

  • Hallo alle zusammen,

    ich würde gerne eine Datenstruktur (Ordnerstruktur) in einem Tree (Baum) speichern. Bisher habe ich das über ein Array gemacht.
    Gibt es auch eine UDF, die einen Baum als so etwas wie eine Variable bereitstellt?
    Sonst muss ich mir eben selbst ein Array schreiben mit entsprechenden Funktionen als UDF. Da wäre eine objektorientierte Sprache natürlich sehr nützlich ;)

    LG

  • Wie meinst du das?
    Es gibt in AutoIt die Möglichkeit Array's in Array's zu speichern.
    Nachteil ist, dass du halt nicht direkt auf die einzelnen Elemente zugreifen kannst:

    [autoit]

    $aGlobal = _GetArr()

    [/autoit][autoit][/autoit][autoit]

    For $aO In $aGlobal
    For $aT In $aO
    ConsoleWrite($aT & @CRLF)
    Next
    Next

    [/autoit][autoit][/autoit][autoit]

    Func _GetArr()
    Local $aLocal1[2]
    Local $aLocal2[2]

    [/autoit][autoit][/autoit][autoit]

    $aLocal1[0] = 1
    $aLocal1[1] = 2
    $aLocal2[0] = $aLocal1
    $aLocal1[0] = 3
    $aLocal1[1] = 4
    $aLocal2[1] = $aLocal1

    [/autoit][autoit][/autoit][autoit]

    Return $aLocal2
    EndFunc

    [/autoit]

    Ob es dafür eine UDF gibt, kp.
    Ich habe zumindest bisher keine gesehen.

  • Was möchtest du eigentlich mit der Baumstruktur erreichen?
    Ich kann mir gerade keinen Reim draus machen wofür man dies bezüglich von Ordnerstrukturen gebrauchen kann.
    Also, was soll dir das bringen wenn du diese als "Tree" vorliegen hast?

  • Schon klar, aber für Ordnerstrukturen eher ungeeignet oder nicht?
    Der einzige Zweck der mir gerade in den Sinn kommt ist, dass man in den Ordnerstrukturen nach bestimmten Dateien sucht.
    Da wäre es doch sinnvoller einfach alle Pfade einzeln aufzulisten und die schnellen String Funktionen zu verwenden.
    Alles in einer Baumstruktur zu hinterlegen und dann wieder jeden "Zweig" abzuklappern ist doch viel zu Zeit-Intensiv.

    Deswegen meine Frage :)

  • Ich würde gerne eine Ordner-Struktur in einem Baum ablegen, die ich aus einer CSV generiere. Im Baum sollen auch Verknüpfungen vorbereitet sein, die später Ordner untereinander verknüpfen. Am liebsten würde ich teilweise auch noch Berechtigungen dort ablegen.
    Diese Ordner- und Berechtigungsstruktur soll anschließend auf einen Fileserver geschrieben werden.

    Bisher habe ich CSV -> in Array -> in Ordner- und Berechtigungsstruktur auf dem Fileserver
    Weil ich momentan so viele Suchoperationen habe, um Kinder und Eltern quer verteilt im Array zu finden, würde ich das am liebsten in einem Baum speichern.

  • Wie meinst du das mit "Ordner untereinander verknüpfen"?
    Normalerweise liegen in Ordner andere Ordner auf denen du zugreifen kannst.
    Aber diese miteinander zu verknüpfen, keine Ahnung was du meinst.

    Zum Glück verstehe ich aber worum es geht.
    Da ich gerade viel zu viel Freizeit habe, setze ich mich mal ran.
    (Hilft denn die UDF von BugFix nicht irgendwie weiter?)

  • Mit Vernküpfungen meine ich ganz normale Windows-Verknüpfungen: https://de.wikipedia.org/wiki/Dateiverkn%C3%BCpfung :)
    Danke dir, dass du dich damit beschäftigst!
    Ja, den Beitrag von BugFix habe ich tatsächlich übersehen :-O Die UDFs helfen mir auf jeden Fall weiter. Man bleibt eben weiterhin auf TreeView angewiesen, allerdings ist es schon einmal eine Hilfe. Was mir bei der UDF von BugFix noch fehlen würde, wäre eine Funktion, mit der ich aus diesem String einzelne Childs anzeigen lassen könnte.
    Ich habe auch schon eine Funktion erstellt, die basierend auf einem Array mir den Pfad des Childs inkl. Eltern angeben kann und eine Funktion, die mir alle Kinder anzeigt.

    Was ist eigentlich schneller? Das über ein Array oder über einen String zu betreiben? Insbesondere, wenn ich öfters nur auf Teile (Knoten) zugreifen möchte?

    • Offizieller Beitrag

    Was ist eigentlich schneller? Das über ein Array oder über einen String zu betreiben?


    - Array ist schnell - aber da kein Direktzugriff musst du jedesmal eine Suche durchführen.
    - Stringbefehle sind sehr schnell
    - überlegenswert ist ein Dictionary einzusetzen, braucht zwar etwas mehr Zeit beim Erstellen, aber das wäre ja einmalig, danach hast du direkten Zugriff - Vorteil gegenüber einem Array. Bedingt aber dass du nur einmalige Schlüssel verwendest

    Letztlich musst du es wohl einfach mal ausprobieren mit welcher Variante du besser fährst.

  • Hallo, ich hab bisher einmal einen "String Tree" und "Array Tree" umgesetzt.
    Im Anhang findest du eine code.au3 und die dazugehörige UDF Tree.au3.

    In der UDF wird lediglich eine Baumstruktur angelegt. Funktionen zum auslesen von Knotenpunkte etc. existieren noch nicht.
    Hole ich aber alles noch nach, wollte quasi nur meinen "Fortschritt" dir mitteilen.

    Kurz zu der UDF:
    Die UDF hat 4 verschiedene Modi's zur Verfügung. 2 davon habe ich bereits umgesetzt, die anderen beiden sind ohne Funktion.
    Um einen bestimmten Modus zu setzen, rufst du die Funktion _Tree_Mode($TREE_XXX) auf. Es sind bereits 4 Globale Variablen vordefiniert:
    $TREE_STRING >> Gibt die Baumstruktur als String aus
    $TREE_ARRAY >> Gibt die Baumstruktur als Array im Array aus
    $TREE_DICTIONARY >> Gibt die Baumstruktur als Dictionary aus (existiert noch nicht)
    $TREE_MAP >> Gibt die Baumstruktur als Map aus (existiert ebenfalls noch nicht, da wäre die AutoIt Version 3.3.13.6 (Beta) mindestens nötig)

    Um nun eine Ordnerstruktur als Baumstruktur auszugeben, benutzt du die Funktion _Tree_Dir(Pfad mit abschließenden Backslash oder Slash!!! >> "\" or "/" <<, Suchtiefe)
    Der Pfad muss halt mit einem Backslash oder Slash enden...
    Bei der Suchtiefe kannst du angeben bis wie weit in die Ordner und Unterordner "geschaut" und abgespeichert werden soll.
    Ist dieser -1, so werden alle Unterordner + Dateien aufgelistet.

    Falls es Fragen gibt, immer fragen.
    Am besten Code ansehen & verstehen und irgendwie ins eigene Projekt einbinden. ^^

  • Hi, damit lässt sich einiges machen. Vielen Dank :)
    Du hast ja das Skript in verschiedene Bereiche durch +++ aufgeteilt. Dazu könnte ich dir auch #region und #endregion empfehlen und mit Strg+T räumt ein automatisches Clean-Up programm das Skript auf: Es fügt Tabs vor den Befehlen ein und entfernt überflüssige, damit sie an der richtigen Stelle stehen, fügt Leerzeichen hinzu bei den Gleichheitszeichen etc. Gibt einige nützliche Funktionen. Was ich besonders hilfreich finde: Es legt eine Backup-Kopie des Skripts in einem Unterordner an bei jedem Durchlauf.

    Meint ihr mit Dictionary bestimmte Schlüsselworte und wo diese im String zu finden sind (Position)?
    Genial fände ich es, wenn das Skript auch noch zu BugFix kompatibel ist. Er schreibt ja "0|Autos" & @CRLF & "0.1|Oldies" & @CRLF

    Gibt es eine Funktion, die Items an eine festgelegte Position im Tree hinzufügt oder löscht? Bei der Einfüge-/Lösch-Operation müsste ja manchmal der ganze Baum umgeschrieben werden oder?

    Ich würde gerne einrichten, dass nur bestimmte Objekte als Item in den Tree aufgenommen werden, z.B. nur Ordner und Vernküpfungen. Ist es sinnvoller dies durch eine Regel-Funktion zu entscheiden oder durch eine Untersuchung des fertigen Strings?
    Beispielsweise habe ich dieses Skript hier erstellt:

    Skript mit Regel-Funktion
    [autoit]


    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    #include <Misc.au3>
    #include <MsgBoxConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Enum $TREE_NONE = -1, $TREE_STRING, $TREE_ARRAY, $TREE_DICTIONARY, $TREE_MAP

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func _Tree_Mode($iMode = -1)
    Local Static $iVar = -1
    $iVar = (($iMode <> -1) ? ($iMode) : ($iVar))
    Return $iVar
    EndFunc ;==>_Tree_Mode

    [/autoit] [autoit][/autoit] [autoit]

    Func _Tree_Dir($sPath, $iLevel = -1)
    Switch _Tree_Mode()
    Case $TREE_NONE
    MsgBox($MB_ICONERROR + $MB_TOPMOST, 'ACHTUNG', 'Die zu benutzende Methode für die Baumstruktur (String, Array, Dictionary oder Map) vorab auswählen!')
    Exit
    Case $TREE_STRING
    Return __Tree_DirString($sPath, $iLevel)
    Case $TREE_ARRAY
    Return __Tree_DirArray($sPath, $iLevel)
    Case $TREE_DICTIONARY
    Case $TREE_MAP
    EndSwitch
    EndFunc ;==>_Tree_Dir

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func __Tree_DirString($sPath, $iLevel)
    Local $vTOne = __Tree_GetNextPath($sPath, 'Regulator')
    Local $vTTwo, $sRet

    [/autoit] [autoit][/autoit] [autoit]

    If $iLevel And $vTOne <> -1 Then
    While $vTOne <> -1
    $sRet &= $iLevel & ' | ' & $vTOne & @CRLF
    $vTTwo = __Tree_DirString($vTOne & '\', $iLevel - 1)
    $vTOne = (($vTTwo <> -1) ? ($vTTwo) : (__Tree_GetNextPath($sPath, 'Regulator')))
    WEnd
    Else
    Return -1
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return StringTrimRight($sRet, 2)
    EndFunc ;==>__Tree_DirString

    [/autoit] [autoit][/autoit] [autoit]

    Func __Tree_DirArray($sPath, $iLevel)
    Local $avTree[1] = [0]
    Local $vTOne = __Tree_GetNextPath($sPath, 'Regulator')
    Local $vTTwo

    [/autoit] [autoit][/autoit] [autoit]

    If $iLevel And $vTOne <> -1 Then
    While $vTOne <> -1
    ReDim $avTree[$avTree[0] + 2]
    $avTree[0] += 1
    $avTree[$avTree[0]] = $vTOne
    $vTTwo = __Tree_DirArray($vTOne & '\', $iLevel - 1)
    $vTOne = (($vTTwo <> -1) ? ($vTTwo) : (__Tree_GetNextPath($sPath, 'Regulator')))
    WEnd
    Else
    Return -1
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return $avTree
    EndFunc ;==>__Tree_DirArray

    [/autoit] [autoit][/autoit] [autoit]

    Func __Tree_DirDictionary($sPath, $iLevel)
    EndFunc ;==>__Tree_DirDictionary

    [/autoit] [autoit][/autoit] [autoit]

    Func __Tree_DirMap($sPath, $iLevel)
    If _VersionCompare(@AutoItVersion, '3.3.13.6') = -1 Then
    MsgBox($MB_ICONERROR + $MB_TOPMOST, 'ACHTUNG', 'Zum benutzen der Map-Funktionen wird mindestens die AutoIt Version 3.3.13.6 (Beta) benötigt! Alternativ das Dictionary Objekt verwenden...')
    Exit
    EndIf
    EndFunc ;==>__Tree_DirMap

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func __Tree_GetNextPath($sPath, $sRegelfunktion, $bClose = False)
    Local Static $avPath[1][2] = [[0, 0]]
    Do
    Local $i, $iFree, $iPos, $sRet, $bRetOK

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $avPath[0][0]
    If Not $iFree And Not $avPath[$i][0] Then $iFree = $i
    If $avPath[$i][0] = $sPath Then
    $iPos = $i
    $i = $avPath[0][0]
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If Not $iPos Then
    If $iFree Then
    $iPos = $iFree
    Else
    ReDim $avPath[$avPath[0][0] + 2][2]
    $avPath[0][0] += 1
    $iPos = $avPath[0][0]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $avPath[$iPos][0] = $sPath
    $avPath[$iPos][1] = FileFindFirstFile($sPath & '*')
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $bClose Then
    FileClose($avPath[$iPos][1])
    $avPath[$iPos][0] = ''
    Return -1
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $sRet = FileFindNextFile($avPath[$iPos][1]) ;Gibt gefundene Objekte zurück
    If @error Then Return __Tree_GetNextPath($avPath[$iPos][0], $sRegelfunktion, True) ;Bricht ab, wenn alles gescannt ist
    $bRetOK = Call($sRegelfunktion, $sPath, $sRet, @extended) ;Ruft Regelfunktion auf, erhält Ergebnis zurück
    If $bRetOK = True Then Return $sPath & $sRet ;Prüft, ob Datei dazugenommen werden soll
    Until $bRetOK = True ;Wiederholt bei false alles
    EndFunc ;==>__Tree_GetNextPath

    [/autoit] [autoit][/autoit] [autoit]

    Func Regulator($sPath, $sRet, $iExtended) ;Prüft, ob Ergebnis Objekt in Tree darf
    If $iExtended Or StringRegExp($sRet, '(?i)\.lnk(?!.)') Then ;Wenn Ordner oder Verknüpfung (*.lnk), dann
    Return True ;Return True
    Else
    Return False
    EndIf
    EndFunc ;==>Regulator

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit]

    Das ist übrigens ein Teil des Projekts https://autoit.de/index.php/Thre…ktive-Directory

  • Zitat von FKFK

    Hi, damit lässt sich einiges machen. Vielen Dank Du hast ja das Skript in verschiedene Bereiche durch +++ aufgeteilt. Dazu könnte ich dir auch #region und #endregion empfehlen und mit Strg+T räumt ein automatisches Clean-Up programm das Skript auf: Es fügt Tabs vor den Befehlen ein und entfernt überflüssige, damit sie an der richtigen Stelle stehen, fügt Leerzeichen hinzu bei den Gleichheitszeichen etc. Gibt einige nützliche Funktionen. Was ich besonders hilfreich finde: Es legt eine Backup-Kopie des Skripts in einem Unterordner an bei jedem Durchlauf.


    Ja, ist mir bereits bekannt. In den 3 Jahren die ich hier schon verbringe habe ich mir jedoch einen eigenen Programmierstil entwickelt. Die Verwendung von #region und #endregion finde ich persönlich nicht so schön, deshalb unterteile ich einzelne Sektionen lieber wie in meinen Skript gezeigt. Zudem zerstört Tidy (Strg+T) schonmal meine Codeeinrückungen. Ich nutze auch schonmal 2 Leerzeichen zwischendurch und die werden einfach durch ein Tab ersetzt. Das stört mich, da kümmer ich mich doch lieber Manuell um alles. ^^

    Zitat von FKFK

    Gibt es eine Funktion, die Items an eine festgelegte Position im Tree hinzufügt oder löscht? Bei der Einfüge-/Lösch-Operation müsste ja manchmal der ganze Baum umgeschrieben werden oder?


    Nein, die Funktion habe ich noch nicht geschrieben. Ob es dazu schon im Netz eine gibt, weiß ich nicht.
    Bei den Array-Tree ist es ziemlich aufwendig neue Daten hinzuzufügen oder alte zu löschen. Daher bietet es sich an einfach einen String zu nehmen, da mit den String Funktionen eigentlich schnell & einfach einzelne Knoten geändert, hinzugefügt oder gar gelöscht werden können. Gleiches gilt auch für Dictionarys (Je nachdem wie man den Baum als Dictionary umsetzt).

    Zitat von FKFK

    Ich würde gerne einrichten, dass nur bestimmte Objekte als Item in den Tree aufgenommen werden, z.B. nur Ordner und Vernküpfungen. Ist es sinnvoller dies durch eine Regel-Funktion zu entscheiden oder durch eine Untersuchung des fertigen Strings?


    Es ist sicherlich sinnvoller direkt eine Regelung festzulegen. Dies hinterher zu löschen ist einfach Zeitaufwendiger. Du gehst quasi den ganzen Baum schon direkt durch beim Erstellen. Warum dann nicht auch direkt schon die Daten filtern? Hinterher NOCHMAL den Baum abzuklappern wäre einfach nur Zeitverschwendung, und davon haben wir Menschen zu wenig. ^^

  • Was hältst du von meiner Regel-Funktion? Mein Hintergedanke war, dass dadurch jeder selbst die Regeln erstellen kann, auf deren Basis die Eingrenzung stattfindet.
    Welche Befehle eignen sich bei String-Einfüge und -Löschoperationen besonders? StringRegexp? StrInStr?
    Der String muss bei jeder Operation neu erstellt werden oder?

  • Schöne Idee ^^
    AutoIt bietet seit neusten die Möglichkeit Funktionen in Variablen abzulegen.
    Guckst du:

    [autoit]

    $hMsg = MsgBox
    $hMsg(0, '', '')

    [/autoit]

    Das bietet die Möglichkeit die Funktion "direkt" zu übergeben und auf die Call Funktion zu verzichten.
    Finde ich persönlich besser. Nur mal so als Hinweis am Rande. :)

    Ja, der String muss dann immer neu erstellt werden. Aber ich wette darauf dass es deutlich schneller ist als mit Array's in Array's zu hantieren.
    Die Stringfunktionen bringen in AutoIt Skripten (wenn richtig eingesetzt) meist immer einen ordentlichen Schub. ^^
    Welche Stringfunktion jetzt für was am besten geeignet ist, muss man mal ausprobieren.
    Kann ich so direkt nicht sagen.

  • Wow, richtig genial :thumbup:
    Wenn ich aus der Variable jetzt noch ein Objekt mit Methoden und Attributen machen könnte wäre AutoIt so ziemlich perfekt, d.h. dass die Variable noch einmal getrennt ansprechbare Eigenschaften und Funktionen enthält. Ich habe irgendwo gelesen, dass es Ansätze in AutoIt gibt, Klassen und Objekte nachzubilden. Weißt du darüber etwas?

    PS: Wie lange ist eigentlich die Zeit bis ich aus dem Forum ausgeloggt werde? Irgendwie werde ich nach dem Schließen der Seite nach einigen Minuten ausgeloggt...

  • Tatsächlich gibt es für AutoIt ein Workaround, welches bedingt OOP zulässt. Ist zwar etwas aufwendiger zu schreiben, hat jedoch die gleiche Logik als ob du mit Objekten arbeiten würdest. Den deutschen Thread dazu findest du hier: AutoItObject - OOP für AutoIt

    Ja. das mit dem ausloggen geht einem auf die Nerven. KA wie lange es dauert bis man gekickt wird. ^^

    €dit: Ach ich sehe gerade, du hattest damals den Thread auch schon gefunden. :D

    Einmal editiert, zuletzt von Yjuq (24. November 2014 um 16:55)

  • Hm, dann bastle ich damit am besten eine Tree-Klasse :)
    Bin jetzt noch am überlegen wegen den Insert- und Delete-Operationen. Sinnvoll wäre hier StringRegExpReplace oder?
    Wie würdest du die Funktion programmieren, um einen Knoten einzufügen oder zu löschen an einer bestimmten Position?