benners Posted April 29 Share Posted April 29 (edited) The title may not make sense so here is the explanation. I am creating a menu structure that is read from an ini file. This structure uses the > character to tell the creating function to either create a menu item or a sub menu. The First array column is the menu structure. The second is the command to execute when the menu is selected. In this ini the commands are empty. If there is only one > character the text following it will be a menu item i.e. Menu>Menu item. Menu will be a top level menu and Menu item will be an item of that menu. If there are two or more, then sub menus will be created i.e. Menu>Submenu>Menuitem. I am trying to sort the array so that it is alphabetically sorted and also sorted so that submenus are before the menu items in there respective top level menus. The menu creation function takes care of this and menus will be created in the order they are in the array. I have attached the ini file with the menu info. The commented section is how the menu should be when the array is sorted. The code is as far as I got before the migraines started It sorts the sub menus. but the items aren't correct. There must be a better more bulletproof way. Thanks #include <Array.au3> #include <StringConstants.au3> ; Read the section from the INI file Local $lines = IniReadSection(@ScriptDir & '\quicklaunch - Copy.ini', 'usermenu') ; Sort the lines alphabetically (descending order) _ArraySort($lines, 0, 1) ; Manually reorder lines based on the number of ">" characters Local $count1 = '' Local $count2 = '' Local $s_Temp0 = '' Local $s_Temp1 = '' For $i = 1 To $lines[0][0] For $j = $i + 1 To $lines[0][0] $count1 = UBound(StringSplit($lines[$i][0], ">", $STR_NOCOUNT)) - 1 $count2 = UBound(StringSplit($lines[$j][0], ">", $STR_NOCOUNT)) - 1 If $count1 < $count2 Then $s_Temp0 = $lines[$i][0] $s_Temp1 = $lines[$i][1] $lines[$i][0] = $lines[$j][0] $lines[$i][1] = $lines[$j][1] $lines[$j][0] = $s_Temp0 $lines[$j][1] = $s_Temp1 EndIf Next Next _ArrayDisplay($lines, 'Sorted By Arrow') QuickLaunch - Copy.ini Edited April 29 by benners Link to comment Share on other sites More sharing options...
SOLVE-SMART Posted April 29 Share Posted April 29 Hi @benners 👋 , why should line 31 and 32 below the four ...Promax>nn... lines? Which kind of sorting should this be? I do not understand the logic. Best regards Sven Stay innovative! Spoiler 🌍 Au3Forums 🎲 AutoIt (en) Cheat Sheet 📊 AutoIt limits/defaults 💎 Code Katas: [...] (comming soon) 🎭 Collection of GitHub users with AutoIt projects 🐞 False-Positives 🔮 Me on GitHub 💬 Opinion about new forum sub category 📑 UDF wiki list ✂ VSCode-AutoItSnippets 📑 WebDriver FAQs 👨🏫 WebDriver Tutorial (coming soon) Link to comment Share on other sites More sharing options...
benners Posted April 29 Author Share Posted April 29 Hi Sven, The lines with the Promax are sub menus under the 2 pasti top menu. The 51, 52 etc are items under that sub menu. Lines 31 and 32 are menu items under the 2 pasti top level menu. When the menu is created, I want the sub menus to be at the top and menu items underneath. Hope that makes sense Thanks. Link to comment Share on other sites More sharing options...
SOLVE-SMART Posted April 29 Share Posted April 29 3 minutes ago, benners said: When the menu is created, I want the sub menus to be at the top and menu items underneath. Ah okay, now I get it (hopefully) 😅 . Okay, hmm let's see ... . Best regards Sven Stay innovative! Spoiler 🌍 Au3Forums 🎲 AutoIt (en) Cheat Sheet 📊 AutoIt limits/defaults 💎 Code Katas: [...] (comming soon) 🎭 Collection of GitHub users with AutoIt projects 🐞 False-Positives 🔮 Me on GitHub 💬 Opinion about new forum sub category 📑 UDF wiki list ✂ VSCode-AutoItSnippets 📑 WebDriver FAQs 👨🏫 WebDriver Tutorial (coming soon) Link to comment Share on other sites More sharing options...
benners Posted April 29 Author Share Posted April 29 I think I have sorted it, in that it sorts the way I want it to now. It will only sort by the first sub menu. Heads gone from thinking about just the first sub menu and not nested ones. expandcollapse popup#include <Array.au3> ; Read the section from the INI file Local $as_Lines = IniReadSection(@ScriptDir & '\quicklaunch - copy.ini', 'usermenu') ; add an extra column for number sorting _ArrayColInsert($as_Lines, 2) ; Sort the lines alphabetically (descending order) _ArraySort($as_Lines, 0, 1) ; Manually reorder lines based on the number of ">" characters Local $s_CurrentMenu = '' Local $s_NewMenu = '' Local $i_SubMenu = 1 Local $i_MenuStart = 1 Local $i_SubMenuStart = 0 For $i = 1 To $as_Lines[0][0] ; get the top level menu text $s_NewMenu = StringRegExp($as_Lines[$i][0], "([^>]+)", 1)[0] ; if this is a new menu then If $s_CurrentMenu <> $s_NewMenu Then $s_CurrentMenu = $s_NewMenu ;_ Set the current menu text $i_MenuStart = $i ;_ Set the position the menu starts at $i_SubMenu = $i_MenuStart ;_ Set the starting menu position for the next sub menu $i_SubMenuStart = 0 ;_ reset the sub menu position EndIf If (UBound(StringSplit($as_Lines[$i][0], ">", $STR_NOCOUNT)) - 1) >= 2 Then ; assume sub menu If $i_SubMenuStart = 0 Then $i_SubMenuStart = $i ; set the first sub menu position $as_Lines[$i][2] = $i_SubMenu ; set the sub menus posiiton on the top level menu ;~ ; re-number the other menu items For $j = $i_MenuStart To $i_SubMenuStart - 1 If $j = 1 Then ; if this is the first array element, increment the menu position by 1 $as_Lines[$j][2] = $i_SubMenu + 1 Else ; $as_Lines[$j][2] = $as_Lines[$j][2] + 1 EndIf Next $i_SubMenu += 1 ; increase the sub menu Else $as_Lines[$i][2] = $i ; write the menu position for the menu item EndIf Next _ArraySort($as_Lines, 0, 1, 0, 2) _ArrayDisplay($as_Lines, 'Sorted By Arrow') Link to comment Share on other sites More sharing options...
Solution AspirinJunkie Posted April 30 Solution Share Posted April 30 In principle, you can sort everything if you only have the right comparison function. However, this is a bit tricky in your case. I have created a corresponding function from your specifications. Now you just need a sort function that accepts a user-defined comparison function. I have used the one from my >>ArrayPlus UDF<< for this and can use it to generate your desired result: #include "ArrayPlus.au3" ; Read the section from the INI file Local $aLines = IniReadSection(@ScriptDir & '\quicklaunch - Copy.ini', 'usermenu') _ArrayDisplay($aLines, "before") _ArraySortFlexible($aLines, __comp_benners, 1) _ArrayDisplay($aLines, "sorted") ; comparison function, which decide which element of two elements of your data is bigger or lesser then the other Func __comp_benners(ByRef $A, ByRef $B) Local $aSplitA = _regex_split($A[0], '^\d+\K\s*|>') Local $aSplitB = _regex_split($B[0], '^\d+\K\s*|>') Local $nA = UBound($aSplitA), $nB = UBound($aSplitB) Local $nMin = $nA > $nB ? $nB : $nA Local $bComp For $i = 0 To $nMin - 2 $bComp = StringCompare($aSplitA[$i], $aSplitB[$i]) If $bComp <> 0 Then Return $bComp Next Return $nA = $nB ? StringCompare($aSplitA[$i], $aSplitB[$i]) : $nA > $nB ? -1 : 1 EndFunc ; like StringSplit - but with regex to choose the delimiter Func _regex_split($sString, Const $sSplitPattern, Const $dFlag = 3) Return StringSplit( _ StringRegExpReplace($sString, $sSplitPattern, Chr(0)), _ Chr(0), $dFlag) EndFunc benners 1 Link to comment Share on other sites More sharing options...
benners Posted April 30 Author Share Posted April 30 That works great thanks. It even sorts the nested sub menus. I have no idea how it does it. I have taken a look at the udf and still none the wiser . I do have a question about some of the functions. A lot have the Const declaration in the optional parameters but when the function is called, these parameters are changed. How does that work? I have never seen this, or can't remember seeing this style before. Thanks again Link to comment Share on other sites More sharing options...
Andreik Posted April 30 Share Posted April 30 Const keyword in function parameters indicates that the value of the parameter will not change during the execution of the function. benners 1 When the words fail... music speaks. Link to comment Share on other sites More sharing options...
benners Posted April 30 Author Share Posted April 30 Cheers. Everyday is a school day Link to comment Share on other sites More sharing options...
AspirinJunkie Posted May 1 Share Posted May 1 18 hours ago, benners said: It even sorts the nested sub menus. I have no idea how it does it. I have taken a look at the udf and still none the wiser You won't find the answer in the UDF code either. There is just a normal array sorting function (with an exchangeable comparison function). The interesting part is in the __comp_benners() function. Sorting is in most cases based on a size comparison of 2 elements. The sorting function goes through the array in a certain pattern - depending on the sorting algorithm - and must always decide which of the two elements it is currently holding is larger than the other. This means that the comparison function is responsible for what the result of a sort looks like. The sorting algorithm itself is only responsible for how to get there. So how do you decide for your case whether an entry in your array is larger (i.e. should be inserted after the smaller element)? In my approach, I take the entries and split them first (regex_split) so that “3 Pasti>Promax>861 & 862” becomes an array with the following content: |3|Pasti|Promax|861 & 862|. The same applies to the comparison value. For example, “3 Pasti>Returns>51” becomes |3|Pasti|Returns|51|. Now the two arrays are compared element by element: 3 = 3 - so nothing is returned yet Pasti = Pasti - so return nothing yet Promax < Returns - so return -1 (means A<B) This is how you work your way through your hierarchy levels. Now comes your special case: If the array sizes are different (because one is a menu and another is a submenu), then this comparison is only carried out up to the second last element. If A has one more element than B, it is returned -1 so that it is sorted before B. As I said, the UDF is not so important - what is important is a suitable comparison function. benners 1 Link to comment Share on other sites More sharing options...
benners Posted May 2 Author Share Posted May 2 Thanks for the explanation. It does a lot for such a small amount of code Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now