Jump to content

Return only Subfolders (Last level only)


Go to solution Solved by Melba23,

Recommended Posts

Hi All,

 

I might mess up on trying to explain, but here goes. 
I read this post about the directory tree level and sorting it by 'hierarchy' or 'level' subfolders.

I tried the exampled and it works great, but how do you return only the Level 6 directory path?
Example:
C:\ = Level 1
C:\Temp = Level 2
C:\Temp\Foo = Level 3
C:\Temp\Foo\Bar = Level 4
C:\Temp\Foo\Bar\Lorem = Level 5
C:\Temp\Foo\Bar\Loren\Epsum = Level 6

Local $aFolderPath, $x = 0
Local $aFolderPaths = _FileListToArrayRec(@ScriptDir, "*", 2, 1, 1, 2)
_ArrayColInsert($aFolderPaths, 1)
For $i = 1 To $aFolderPaths[0][0]
    $aFolderPath = StringSplit($aFolderPaths[$i][0], "\")
    If _ArraySearch($aFolderPaths, Number($aFolderPath[0] & "." & $x), 1, 0, 0, 0, 1, 1) > -1 Then
        $x += 1
        $aFolderPaths[$i][1] = Number($aFolderPath[0] & "." & $x)
    Else
        $x = 0
        While _ArraySearch($aFolderPaths, Number($aFolderPath[0] & "." & $x), 1, 0, 0, 0, 1, 1) > -1
            $x += 1
        WEnd
        $aFolderPaths[$i][1] = Number($aFolderPath[0] & "." & $x)
    EndIf
Next
_ArraySort($aFolderPaths, 1, 1, 0, 1)
_ArrayDisplay($aFolderPaths)

Directory Tree Level

Kind Regards
Skeletor

"Coffee: my defense against going postal."

Microsoft Office Splash Screen | Basic Notepad Program (Beginner) | Transparent Splash Screen | Full Screen UI

Link to comment
Share on other sites

  • Moderators

Skeletor,

If you replace @ScriptDir with the full path of that level, the function will return folders from that level.

There is an option to search down for a defined number of levels, but if you want to look for all Level 6 folders on the path, regardless of on which branch they reside, then you will have to get all the folders down to that level and then extract only those with the corresponding number of backslashes.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

@Melba23 - thanks for the advise. After reading over your comment about 7 or 8 time, I got working on this, I finally found the answer.
However, is this the right way to do this? Would like to know if my method is logical?

 

#include <Array.au3>
#include <File.au3>
#include <MsgBoxConstants.au3>

Local $aFolderPath, $x = 0

$aFolderPaths = _FileListToArrayRec(@UserProfileDir, "*", $FLTAR_FOLDERS, $FLTAR_RECUR, $FLTAR_SORT, $FLTAR_FULLPATH)

_ArrayColInsert($aFolderPaths, 1)
For $i = 1 To $aFolderPaths[0][0]
    $aFolderPath = StringSplit($aFolderPaths[$i][0], "\")
    If _ArraySearch($aFolderPaths, Number($aFolderPath[0] & "." & $x), 1, 0, 0, 0, 1, 1) > -1 Then
        $x += 1
        $aFolderPaths[$i][1] = Number($aFolderPath[0]) ; Removed this => (& "." & $x) from Number($aFolderPath[0] & "." & $x)
    Else
        $x = 0
        While _ArraySearch($aFolderPaths, Number($aFolderPath[0]), 1, 0, 0, 0, 1, 1) > -1  ; Removed this => (& "." & $x) from Number($aFolderPath[0] & "." & $x)
            $x += 1
        WEnd
        $aFolderPaths[$i][1] = Number($aFolderPath[0] & "." & $x)
    EndIf
Next
_ArraySort($aFolderPaths, 1, 1, 0, 1)
_ArrayDisplay($aFolderPaths)

Local $FindArray = _ArrayFindAll($aFolderPaths, "6", Default, Default, Default, Default, 2) ; Searching for only Level 6 folder.

Local $aFolderPathsCol[UBound($FindArray)][UBound($aFolderPaths, 2)]

For $i = 0 To UBound($FindArray) -1
    For $iI = 0 To UBound($aFolderPaths, 2) -1
        $aFolderPathsCol[$i][$iI] = $aFolderPaths [$FindArray[$i]] [$iI]
    Next
Next
_ArraySort($aFolderPathsCol,1)
_ArrayColDelete($aFolderPathsCol,1)
_ArrayDisplay($aFolderPathsCol)

 

Array = Achilles Heel for me.

Kind Regards
Skeletor

"Coffee: my defense against going postal."

Microsoft Office Splash Screen | Basic Notepad Program (Beginner) | Transparent Splash Screen | Full Screen UI

Link to comment
Share on other sites

  • Moderators
  • Solution

Skeletor,

I would do it this way:

#include <Array.au3>
#include <File.au3>

; Get the list of all folders
$aFolderPaths = _FileListToArrayRec("M:", "*", $FLTAR_FOLDERS, $FLTAR_RECUR, $FLTAR_SORT, $FLTAR_FULLPATH)

; This will be the list of indices of folders to delete
$sDeleteString = ""

For $i = 1 To $aFolderPaths[0]
    ; Count number of "\"
    StringReplace($aFolderPaths[$i], "\", "")
    ; It is returned in @extended
    If @extended <> 6 Then
        ; If not at level 6 then add index of item to list to delete
        $sDeleteString &= $i & ";"
    EndIf

Next

; Trim the finla and unwanted ";"
$sDeleteString = StringTrimRight($sDeleteString, 1)

; Delete all the unwanted folders in one go
_ArrayDelete($aFolderPaths, $sDeleteString)

; Reset the count
$aFolderPaths[0] = UBound($aFolderPaths) - 1

; And here we are!
_ArrayDisplay($aFolderPaths, "", Default, 8)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

@Melba23 .. This is simply amazing. 
To be honest, I never knew about the macro @extended, 
I have learnt something new today. 

Thank you for adding comments into the code, it helps me a lot to know what each section does and why it does it. 

THANK YOU!

 

Kind Regards
Skeletor

"Coffee: my defense against going postal."

Microsoft Office Splash Screen | Basic Notepad Program (Beginner) | Transparent Splash Screen | Full Screen UI

Link to comment
Share on other sites

@Melba23 I like your way of using StringReplace() just for counting the number of times a character is found in a string (@extended) without assigning the result to a new string.

I guess most of us don't think at this solution as often as we should, probably thinking unconsciously to this syntax...

Local $sString = StringReplace()

...and not to the syntax you used :

StringReplace() ; string returned won't be used, but @extended will.

The original string is untouched in both cases, which seems unconsciously "a bit" less obvious with the syntax you used.

Not sure I expressed this clearly, but you got the idea :)
 

Edited by pixelsearch
typo
Link to comment
Share on other sites

If you look at this link ("Count characters in a string") you'll see that the question was already asked and several answers were made (including @Jos alternative StringReplace)

I'm pretty sure @Jon could add a quick C++ function in 5 minutes, maybe called "StringCount" where no string would need to be prepared and returned in the code (faster result) but only the number of times a character (or group of characters) are found in a string.

Then we won't need to use the StringReplace alternative at all, keeping StringReplace to its natural behavior : return a string with replaced characters.

Just my 2 cts...

Link to comment
Share on other sites

There is no need to scan the entire drive for getting this done You can withdraw the search once the desired depth level has been reached.  using a strategy, it is easy to determine what results should be added to the array using the functions FindFirstFile() FileFindNextFile() 
if you need an example for this i'll put it up so you can try it out

Link to comment
Share on other sites

My 2 cents - for the fun (obviously)  :>

#include <Array.au3>
#include <File.au3>

; Get the list of all folders
$aFolderPaths = _FileListToArrayRec(@desktopdir, "*", $FLTAR_FOLDERS, $FLTAR_RECUR, $FLTAR_SORT, $FLTAR_FULLPATH)

$k = 1
Local $aResults[1000]

For $i = 1 To $aFolderPaths[0]
    $tmp = StringRegExpReplace($aFolderPaths[$i], '^((?:[^\\]+\\){6}[^\\]+)$', "$1")
    If @extended Then 
        $aResults[$k] = $tmp
        $k += 1
    EndIf
Next

$aResults[0] = $k
ReDim $aResults[$k]

_ArrayDisplay($aResults)

 

Link to comment
Share on other sites

Pathes of the form \\server... or C:\temp\.\.\.\.\... escape that pattern.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Another 2 cents to speed up the process:

_FileListToArrayRec() will go through all the deeper folder levels, which are of no interest here. So with this code all levels beyond "6" will be ignored, speeding up the whole process:

#include <File.au3>
#include <Array.au3>
#include <Debug.au3>




$StartDir="C:\" ; " just for preserving the online forum formatting

$StrHarvester=""
$Deepth=0
$CurrentDir=""

AdlibRegister("Status",2000)

harvest($StartDir)
AdlibUnRegister("Status")
ToolTip("Done, Processing results...",100,100)
; strip off the final "|"
$StrHarvester=StringTrimRight($StrHarvester,1)
$aLevel_6_Dirs=StringSplit($StrHarvester,"|")
_DebugArrayDisplay($aLevel_6_Dirs)


Func harvest($_Dir)
    $Deepth+=1
    $CurrentDir=$_Dir
    Local $aNextLevel
    $aNextLevel=_FileListToArray($_Dir,"*",2,1)
    if IsArray($aNextLevel) Then
    Switch $Deepth
        case 1 to 5 ; loop through next level
            Local $x
            for $x = 1 to $aNextLevel[0]
                if $aNextLevel[$x] = "." or $aNextLevel[$x] = ".." then
                    ContinueLoop
                Else
                    harvest($aNextLevel[$x])
                EndIf
            Next
        case 6 ; add all found subdirs to the result string
            $StrHarvester &= _ArrayToString($aNextLevel,"|",1) & "|"
        case else ; ups, here we should never arrive!
            MsgBox(0, 'Gone too deep', "Level = " & $Deepth & @CRLF & _
            $_Dir)
    EndSwitch
    Else
        ; no subdirs at this level
    EndIf
    $Deepth-=1
    Return
EndFunc


Func Status()
    ToolTip($CurrentDir,MouseGetPos(0),MouseGetPos(1),"Level = " & $Deepth)
    ConsoleWrite($Deepth & @TAB & $CurrentDir & @CRLF)
EndFunc

 

 

 

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

  • Moderators

Hi,

Quote

_FileListToArrayRec() will go through all the deeper folder levels, which are of no interest here. 

Not so. You can limit how far it goes into the tree by using negative values in the $iRecur parameter. In this case:

$aFolderPaths = _FileListToArrayRec("M:", "*", $FLTAR_FOLDERS, -6, $FLTAR_SORT, $FLTAR_FULLPATH)

will not go any deeper than you require.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...