Jump to content
TheDcoder

Sorting a 2D array by version

Recommended Posts

Hi, I have a 2D array with 2 columns, the 1st column contains a "version string" and the 2nd column contains a generic string. I want to sort it in the descending order so the latest version comes first.

#include <Array.au3>

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

_ArraySort($aVersionsAndReleases, 1)
ConsoleWrite(_ArrayToString($aVersionsAndReleases, ' - '))
_ArrayDisplay($aVersionsAndReleases)

Unfortunately, _ArraySort isn't working here :(. This is the output generated by the script:

0.2.9.11 - Release #4
0.2.9.10 - Release #3
0.2.8.9 - Release #1
0.2.8.10 - Release #2

The expected result should be:

0.2.9.11 - Release #4
0.2.9.10 - Release #3
0.2.8.10 - Release #2
0.2.8.9 - Release #1

I am looking to develop an function which does this... but I don't know where to start :(. Can someone help me get started? Thanks in Advance! :D

- TD.


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

I've written a sorting function for user defined sorting (see the UDF in attachment) .
With this the solution should be something like this:

#include "DynArray.au3"

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

_ArraySortFlexible($aVersionsAndReleases, _MyCompare)
_ArrayDisplay($aVersionsAndReleases)


; user defined comparison function for user-defined sorting
Func _MyCompare(ByRef $A, ByRef $B)
    Local Static $h_DLL_Shlwapi = DllOpen("Shlwapi.dll")

    Return -DllCall($h_DLL_Shlwapi, "int", "StrCmpLogicalW", "wstr", $A[0], "wstr", $B[0])[0]
EndFunc   ;==>_MyCompare

 

DynArray.au3

Edited by AspirinJunkie
shorter comparison function

Share this post


Link to post
Share on other sites

Here is an option with some good old fashioned programming logic:

#include <Array.au3>

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

ReDim $aVersionsAndReleases[4][3]
For $x = 0 To UBound($aVersionsAndReleases) - 1
    $Version = StringSplit($aVersionsAndReleases[$x][0], ".")
    For $y = 1 To $Version[0]
        $aVersionsAndReleases[$x][2] &= StringRight("000000" & $Version[$y], 6)
    Next
Next
_ArraySort($aVersionsAndReleases, 1, 0, 0, 2)
ConsoleWrite(_ArrayToString($aVersionsAndReleases, ' - '))
_ArrayDisplay($aVersionsAndReleases)

Jos


SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

@czardas I have looked into natural sort but most of them only talk about a single number... not multiple digits in a single column! I will look into them anyway. Now I know what natural sort is :D.

@Jos That's quick hack you have got there! :o. Never thought that it would be that simple :P:thumbsup:

@AspirinJunkie Your UDF looks very promising, I will give it a go :).

I will post back with the results which I finish playing around with the solutions. Thanks for post y'all! Much Appreciated! :D


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

In the end, I decided to go with @wraithdu's _ArrayNaturalSort. Just what I needed! :thumbsup:

#include <Array.au3>
#include <StringConstants.au3>

#Region Include Functions
; #FUNCTION# ====================================================================================================================
; Name ..........: _ArrayCustomSort
; Description ...: Sort a 1D or 2D array on a specific index using the quicksort/insertionsort algorithms, based on a custom sorting function.
; Syntax ........: _ArrayCustomSort(Byref $avArray, $sSortFunc[, $iDescending = 0[, $iStart = 0[, $iEnd = 0[, $iSubItem = 0]]]])
; Parameters ....: $avArray             - [in/out] Array to sort
;                  $sSortFunc           - Name of custom sorting function. See Remarks for usage.
;                  $iDescending         - [optional] If set to 1, sort descendingly
;                  $iStart              - [optional] Index of array to start sorting at
;                  $iEnd                - [optional] Index of array to stop sorting at
;                  $iSubItem            - [optional] Sub-index to sort on in 2D arrays
; Return values .: Success - 1
;                  Failure - 0, sets @error:
;                  |1 - $avArray is not an array
;                  |2 - $iStart is greater than $iEnd
;                  |3 - $iSubItem is greater than subitem count
;                  |4 - $avArray has too many dimensions
;                  |5 - Invalid sort function
; Author ........: Erik Pilsits
; Modified ......: Erik Pilsits - removed IsNumber testing, LazyCoder - added $iSubItem option, Tylo - implemented stable QuickSort algo, Jos van der Zande - changed logic to correctly Sort arrays with mixed Values and Strings, Ultima - major optimization, code cleanup, removed $i_Dim parameter
; Remarks .......: Sorting function is called with two array elements as arguments. The function should return
;                  0 if they are equal,
;                  -1 if element one comes before element two,
;                  1 if element one comes after element two.
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _ArrayCustomSort(ByRef $avArray, $sSortFunc, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0)
    If Not IsArray($avArray) Then Return SetError(1, 0, 0)
    If Not IsString($sSortFunc) Then Return SetError(5, 0, 0)

    Local $iUBound = UBound($avArray) - 1

    ; Bounds checking
    If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound
    If $iStart < 0 Then $iStart = 0
    If $iStart > $iEnd Then Return SetError(2, 0, 0)

    ; Sort
    Switch UBound($avArray, 0)
        Case 1
            __ArrayCustomQuickSort1D($avArray, $sSortFunc, $iStart, $iEnd)
            If $iDescending Then _ArrayReverse($avArray, $iStart, $iEnd)
        Case 2
            Local $iSubMax = UBound($avArray, 2) - 1
            If $iSubItem > $iSubMax Then Return SetError(3, 0, 0)

            If $iDescending Then
                $iDescending = -1
            Else
                $iDescending = 1
            EndIf

            __ArrayCustomQuickSort2D($avArray, $sSortFunc, $iDescending, $iStart, $iEnd, $iSubItem, $iSubMax)
        Case Else
            Return SetError(4, 0, 0)
    EndSwitch

    Return 1
EndFunc   ;==>_ArrayCustomSort

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: __ArrayCustomQuickSort1D
; Description ...: Helper function for sorting 1D arrays
; Syntax.........: __ArrayCustomQuickSort1D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStart, ByRef $iEnd)
; Parameters ....: $avArray   - Array to sort
;                  $sSortFunc - Name of sorting function.
;                  $iStart    - Index of array to start sorting at
;                  $iEnd      - Index of array to stop sorting at
; Return values .: None
; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima
; Modified.......: Erik Pilsits - removed IsNumber testing
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================
Func __ArrayCustomQuickSort1D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStart, ByRef $iEnd)
    If $iEnd <= $iStart Then Return

    Local $vTmp

    ; InsertionSort (faster for smaller segments)
    If ($iEnd - $iStart) < 15 Then
        Local $i, $j
        For $i = $iStart + 1 To $iEnd
            $vTmp = $avArray[$i]
            For $j = $i - 1 To $iStart Step -1
                If (Call($sSortFunc, $vTmp, $avArray[$j]) >= 0) Then ExitLoop
                $avArray[$j + 1] = $avArray[$j]
            Next
            $avArray[$j + 1] = $vTmp
        Next
        Return
    EndIf

    ; QuickSort
    Local $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)]
    Do
        While (Call($sSortFunc, $avArray[$L], $vPivot) < 0)
            $L += 1
        WEnd
        While (Call($sSortFunc, $avArray[$R], $vPivot) > 0)
            $R -= 1
        WEnd

        ; Swap
        If $L <= $R Then
            $vTmp = $avArray[$L]
            $avArray[$L] = $avArray[$R]
            $avArray[$R] = $vTmp
            $L += 1
            $R -= 1
        EndIf
    Until $L > $R

    __ArrayCustomQuickSort1D($avArray, $sSortFunc, $iStart, $R)
    __ArrayCustomQuickSort1D($avArray, $sSortFunc, $L, $iEnd)
EndFunc   ;==>__ArrayCustomQuickSort1D

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: __ArrayCustomQuickSort2D
; Description ...: Helper function for sorting 2D arrays
; Syntax.........: __ArrayCustomQuickSort2D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax)
; Parameters ....: $avArray  - Array to sort
;                  $iStep    - Step size (should be 1 to sort ascending, -1 to sort descending!)
;                  $iStart   - Index of array to start sorting at
;                  $iEnd     - Index of array to stop sorting at
;                  $iSubItem - Sub-index to sort on in 2D arrays
;                  $iSubMax  - Maximum sub-index that array has
; Return values .: None
; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima
; Modified.......: Erik Pilsits - removed IsNumber testing
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================
Func __ArrayCustomQuickSort2D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax)
    If $iEnd <= $iStart Then Return

    ; QuickSort
    Local $i, $vTmp, $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)][$iSubItem]
    Do
        While ($iStep * Call($sSortFunc, $avArray[$L][$iSubItem], $vPivot) < 0)
            $L += 1
        WEnd
        While ($iStep * Call($sSortFunc, $avArray[$R][$iSubItem], $vPivot) > 0)
            $R -= 1
        WEnd

        ; Swap
        If $L <= $R Then
            For $i = 0 To $iSubMax
                $vTmp = $avArray[$L][$i]
                $avArray[$L][$i] = $avArray[$R][$i]
                $avArray[$R][$i] = $vTmp
            Next
            $L += 1
            $R -= 1
        EndIf
    Until $L > $R

    __ArrayCustomQuickSort2D($avArray, $sSortFunc, $iStep, $iStart, $R, $iSubItem, $iSubMax)
    __ArrayCustomQuickSort2D($avArray, $sSortFunc, $iStep, $L, $iEnd, $iSubItem, $iSubMax)
EndFunc   ;==>__ArrayCustomQuickSort2D

; #FUNCTION# ====================================================================================================================
; Name...........: _NaturalCompare
; Description ...: Compare two strings using Natural (Alphabetical) sorting.
; Syntax.........: _NaturalCompare($s1, $s2[, $iCase = 0])
; Parameters ....: $s1, $s2 - Strings to compare
;                  $iCase   - [Optional] Case sensitive or insensitive comparison
;                  |0 - Case insensitive (default)
;                  |1 - Case sensitive
; Return values .: Success - One of the following:
;                  |0  - Strings are equal
;                  |-1 - $s1 comes before $s2
;                  |1  - $s1 goes after $s2
;                  Failure - Returns -2 and Sets @Error:
;                  |1 - $s1 or $s2 is not a string
;                  |2 - $iCase is invalid
; Author ........: Erik Pilsits
; Modified.......:
; Remarks .......: Original algorithm by Dave Koelle
; Related .......: StringCompare
; Link ..........: http://www.davekoelle.com/alphanum.html
; Example .......: Yes
; ===============================================================================================================================
Func _NaturalCompare($s1, $s2, $iCase = 0)
    ; check params
    If (Not IsString($s1)) Then $s1 = String($s1)
    If (Not IsString($s2)) Then $s2 = String($s2)
    ; check case, set default
    If $iCase <> 0 And $iCase <> 1 Then $iCase = 0

    Local $n = 0
    Local $s1chunk, $s2chunk
    Local $idx, $i1chunk, $i2chunk
    Local $s1temp, $s2temp

    While $n = 0
        ; get next chunk
        ; STRING 1
        $s1chunk = StringRegExp($s1, "^(\d+|\D+)", 1)
        If @error Then
            $s1chunk = ""
        Else
            $s1chunk = $s1chunk[0]
        EndIf
        ; STRING 2
        $s2chunk = StringRegExp($s2, "^(\d+|\D+)", 1)
        If @error Then
            $s2chunk = ""
        Else
            $s2chunk = $s2chunk[0]
        EndIf

        ; ran out of chunks, strings are the same, return 0
        If $s1chunk = "" And $s2chunk = "" Then Return 0

        ; remove chunks from strings
        $s1 = StringMid($s1, StringLen($s1chunk) + 1)
        $s2 = StringMid($s2, StringLen($s2chunk) + 1)

        Select
            ; Case 1: both chunks contain letters
            Case (Not StringIsDigit($s1chunk)) And (Not StringIsDigit($s2chunk))
                $n = StringCompare($s1chunk, $s2chunk, $iCase)
            ; Case 2: both chunks contain numbers
            Case StringIsDigit($s1chunk) And StringIsDigit($s2chunk)
                ; strip leading 0's
                $s1temp = $s1chunk
                $s2temp = $s2chunk
                $s1chunk = StringRegExpReplace($s1chunk, "^0*", "")
                $s2chunk = StringRegExpReplace($s2chunk, "^0*", "")
                ; record number of stripped 0's
                $s1temp = StringLen($s1temp) - StringLen($s1chunk)
                $s2temp = StringLen($s2temp) - StringLen($s2chunk)
                ; first check if one string is longer than the other, meaning a bigger number
                If StringLen($s1chunk) > StringLen($s2chunk) Then
                    Return 1
                ElseIf StringLen($s1chunk) < StringLen($s2chunk) Then
                    Return -1
                EndIf
                ; strings are equal length
                ; compare 8 digits at a time, starting from the left, to avoid overflow
                $idx = 1
                While 1
                    $i1chunk = Int(StringMid($s1chunk, $idx, 8))
                    $i2chunk = Int(StringMid($s2chunk, $idx, 8))
                    ; check for end of string
                    If $i1chunk = "" And $i2chunk = "" Then
                        ; check number of leading 0's removed, if any - windows sorts more leading 0's above fewer leading 0's, ie 00001 < 0001 < 001
                        If $s1temp > $s2temp Then
                            Return -1
                        ElseIf $s1temp < $s2temp Then
                            Return 1
                        Else
                            ; numbers are equal
                            ExitLoop
                        EndIf
                    EndIf
                    ; valid numbers, so compare
                    If $i1chunk > $i2chunk Then
                        Return 1
                    ElseIf $i1chunk < $i2chunk Then
                        Return -1
                    EndIf
                    ; chunks are equal, get next chunk of digits
                    $idx += 8
                WEnd
            ; Case 3: one chunk has letters, the other has numbers; or one is empty
            Case Else
                ; if we get here, this should be the last and deciding test, so return the result
                Return StringCompare($s1chunk, $s2chunk, $iCase)
        EndSelect
    WEnd

    Return $n
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _ArrayNaturalSort
; Description ...: Sort a 1D or 2D array on a specific index using the quicksort/insertionsort algorithms.
; Syntax.........: _ArrayNaturalSort(ByRef $avArray[, $iDescending = 0[, $iStart = 0[, $iEnd = 0[, $iSubItem = 0]]]])
; Parameters ....: $avArray     - Array to sort
;                  $iDescending - [optional] If set to 1, sort descendingly
;                  $iStart      - [optional] Index of array to start sorting at
;                  $iEnd        - [optional] Index of array to stop sorting at
;                  $iSubItem    - [optional] Sub-index to sort on in 2D arrays
; Return values .: Success - 1
;                  Failure - 0, sets @error:
;                  |1 - $avArray is not an array
;                  |2 - $iStart is greater than $iEnd
;                  |3 - $iSubItem is greater than subitem count
;                  |4 - $avArray has too many dimensions
;                  |5 - Invalid sort function
; Author ........: Erik Pilsits
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........: https://www.autoitscript.com/forum/topic/83626-natural-order-string-comparison/
; Example .......: No
; ===============================================================================================================================
Func _ArrayNaturalSort(ByRef $avArray, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0)
    Return _ArrayCustomSort($avArray, "_NaturalCompare", $iDescending, $iStart, $iEnd, $iSubItem)
EndFunc   ;==>_ArrayNaturalSort
#EndRegion

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

_ArrayNaturalSort($aVersionsAndReleases, 1)
ConsoleWrite(_ArrayToString($aVersionsAndReleases, ' - '))
_ArrayDisplay($aVersionsAndReleases)

 

Edited by TheDcoder
Forgot to add the link to wraithdu's thread

AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

A variant of Jos version, mucho classic too  :)

Local $aVersionsAndReleases[5][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"], ["0.3", "Release #3"]]

ReDim $aVersionsAndReleases[5][3]
For $x = 0 To UBound($aVersionsAndReleases) - 1
    $Version = StringSplit($aVersionsAndReleases[$x][0], ".")
    For $y = 1 To $Version[0]
        $aVersionsAndReleases[$x][2] &= StringFormat("%03i", $Version[$y])
    Next
Next
_ArraySort($aVersionsAndReleases, 1, 0, 0, 2)
ConsoleWrite(_ArrayToString($aVersionsAndReleases, ' - '))
_ArrayDisplay($aVersionsAndReleases)

 

Share this post


Link to post
Share on other sites

Natural sort is more flexible however, for a bespoke situation such as this, it could be considered overkill. I tend to strip away things I don't need once everything is working, so I quite often use a standard function with all the bells and whistles attached before making final adjustments. This approach can sometimes be useful when you are unsure of all the features you intend to implement: eventually you might want to keep the whistles and get rid of the bells. I don't think there is a right or wrong approach to this and the methods above are all valid. :)

Edited by czardas

Share this post


Link to post
Share on other sites

Well said @czardas :D.


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

This method converts a[.b[.c[.d]]]] to 00a[00b[00c[00d]]]] (Where abcd are digits.) by executing a string from a StringRegExpReplace function.

It works on a 1D or 2D array.

#include <Array.au3>

Local $aVersionsAndReleases[6][2] = [["0.2.8.9", "Release #2"], ["0.2.9.10", "Release #1"], ["0.2.8", "Release #1"], _
                                     ["0.2.7.10", "Release #1"], ["0.2.9.11", "Release #2"], ["0.3", "Release #1"]]
; Or try
;Local $aVersionsAndReleases[6] = ["0.2.8.9", "0.2.9.10", "0.2.8", "0.2.7.10", "0.2.9.11", "0.3"] ; 1D array

_ArrayColInsert($aVersionsAndReleases, 0) ; Add a new column, Col 0.
For $x = 0 To UBound($aVersionsAndReleases) - 1
    $aVersionsAndReleases[$x][0] = Execute(StringTrimRight(StringRegExpReplace($aVersionsAndReleases[$x][1], "(\d+)\.?", _
              'StringRight("000${1}", 3) & '), 3)) ; Converts a[.b[.c[.d]]]] to 00a[00b[00c[00d]]]] Where abcd are digits.
    ;ConsoleWrite(StringRegExpReplace($aVersionsAndReleases[$x][1], "(\d+)\.?", 'StringRight("000${1}", 3) & ') & @CRLF)
Next
_ArraySort($aVersionsAndReleases, 1, 0, 0, 0)
ConsoleWrite(_ArrayToString($aVersionsAndReleases, ' - '))
_ArrayColDelete($aVersionsAndReleases, 0, True) ; Now delete the added column.
_ArrayDisplay($aVersionsAndReleases)

 

Share this post


Link to post
Share on other sites

More RegEx magic. Thanks for the code @Malkey :)


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

edit: super late as per usual

I ended up with the Jos/Malkey answer as well, but with no want to fix the formatting after altered.

#include <Array.au3>

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.10", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

for $i = 0 to ubound($aVersionsAndReleases) - 1
    $aSplit = stringsplit($aVersionsAndReleases[$i][0] , "." , 2)
    $aSplit[ubound($aSplit) - 1] = StringFormat("%02i" , $aSplit[ubound($aSplit) - 1])
    $aVersionsAndReleases[$i][0] = _ArrayToString($aSplit , ".")
next

_ArraySort($aVersionsAndReleases, 1)
_ArrayDisplay($aVersionsAndReleases)

 

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites
4 minutes ago, iamtheky said:

but with no want to fix the formatting after altered.

I needed a solution which fixes the version string after the sorting because those version numbers are displayed to the user and I do not want the user get confused! Albeit, it is a nice way if you want to sort the array internally :)


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

nah, its probably slower than the regexp if you are going to send it through formatting a second time.  

I havent seen a good race thread in a while, version sort could stand to go through the wringer.

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

I had a similar case here :

using the regexp provided on post # 7 of that topic, here's another shot:

#include <array.au3>
Local $aVersionsAndReleases[][] = [["0.2.8.9", "Release #1"],["0.2.9.10", "Release #3"],["0.2.9.11", "Release #4"],["0.2.8.10", "Release #2"],["0.3", "Release #5"]]
;
For $i = 0 To UBound($aVersionsAndReleases) - 1
    $aVersionsAndReleases[$i][0] = StringRegExpReplace($aVersionsAndReleases[$i][0], '(?<!\d)(\d)(?!\d)', '0\1')
Next
;
_ArraySort($aVersionsAndReleases, 1, 0, 0, 0)
_ArrayDisplay($aVersionsAndReleases)

 


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

RegEx for the rescue again, thanks for sharing the code :)


AutoIt.4.Life Clubrooms - Life is like a Donut (secret key)

Spoiler

My contributions to the AutoIt Community

If I have hurt or offended you in anyway, Please accept my apologies, I never (regardless of the situation) mean to do that to anybody!!!

3fHNZJ.gif

PLEASE JOIN ##AutoIt AND HELP THE IRC AUTOIT COMMUNITY!

Share this post


Link to post
Share on other sites

*Fixed in post #19

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

my bad, somehow removed the type 2s (to remove the ubound count) from my stringsplits

#include <Array.au3>

Local $aVersionsAndReleases[4][2] = [["0.2.8.9", "Release #1"], ["0.2.9.1", "Release #3"], ["0.2.9.11", "Release #4"], ["0.2.8.10", "Release #2"]]

_ArraySort($aVersionsAndReleases, 1)

for $i = 1 to ubound($aVersionsAndReleases) - 1


If StringSplit($aVersionsAndReleases[$i][0] , "." , 2)[0] = StringSplit($aVersionsAndReleases[$i - 1][0] , "." , 2)[0] AND StringSplit($aVersionsAndReleases[$i][0] , "." , 2)[1] = StringSplit($aVersionsAndReleases[$i - 1][0] , "." , 2)[1] AND StringSplit($aVersionsAndReleases[$i][0] , "." , 2)[2] = StringSplit($aVersionsAndReleases[$i - 1][0] , "." , 2)[2] AND execute(StringReplace($aVersionsAndReleases[$i][0] , "." , "+")) > execute(StringReplace($aVersionsAndReleases[$i - 1][0] , "." , "+")) Then _ArraySwap($aVersionsAndReleases , $i , $i - 1)


next

_ArrayDisplay($aVersionsAndReleases)

 

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites

 @iamtheky

Try with this array in your example of post #19.

Local $aVersionsAndReleases[4][2] = [["0.2.9.4", "Release #1"], ["0.2.9.21", "Release #4"], ["0.2.9.11", "Release #3"], ["0.2.9.5", "Release #2"]]

 

Share this post


Link to post
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

  • Similar Content

    • By nacerbaaziz
      good morning everybody.
      today i liked to share an small example with you
      which it an function to read the registry values as an array
      the result array is 2d array witch
      $a_array[n][0] = value name
      $a_array[n][1] = value Data
      $a_array[0][0] = values count
      here's the function

      #include <Array.au3> #include <WinAPIReg.au3> #include <APIRegConstants.au3> Local $a_array = _RegReadToArray("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run") If @error Then     MsgBox(16, "error", @error)     Exit EndIf _ArrayDisplay($a_array) Func _RegReadToArray($s_RegKey)     Local $a_KeySplitInfo = StringSplit($s_RegKey, "\\", 2)     If UBound($a_KeySplitInfo) <= 1 Then         $a_KeySplitInfo = StringSplit($s_RegKey, "\", 2)         If UBound($a_KeySplitInfo) <= 1 Then Return (1, 1, 0)     EndIf     Local $H_KeyInfo = "", $s_RegKeyInfo = ""     Switch $a_KeySplitInfo[0]         Case "hklm", "HKEY_LOCAL_MACHINE", "hklm64", "HKEY_LOCAL_MACHINE64"             $H_KeyInfo = $HKEY_LOCAL_MACHINE         Case "hkCu", "HKEY_CURRENT_USER", "hkCU64", "HKEY_CURRENT_USER64"             $H_KeyInfo = $HKEY_CURRENT_USER         Case "hkCr", "HKEY_CLASSES_ROOT", "HKCR64", "HKEY_CLASSES_ROOT64"             $H_KeyInfo = $HKEY_CLASSES_ROOT         Case "HKU", "HKEY_USERS", "HKU64", "HKEY_USERS64"             $H_KeyInfo = $HKEY_USERS         Case Else             Return SetError(2, 2, 0)     EndSwitch     _ArrayDelete($a_KeySplitInfo, 0)     $s_RegKeyInfo = _ArrayToString($a_KeySplitInfo, "\")     Local $H_KeyInfoOpen = _WinAPI_RegOpenKey($H_KeyInfo, $s_RegKeyInfo, $KEY_READ)     Local $A_KeyInfo = _WinAPI_RegQueryInfoKey($H_KeyInfoOpen)     If @error Then Return SetError(1, 1, 0)     _WinAPI_RegCloseKey($H_KeyInfoOpen)     Local $A_RegVal[$A_KeyInfo[2] + 1][2]     Local $iV = 1, $s_RegRead = ""     While 1         $s_RegVal = RegEnumVal($s_RegKey, $iV)         If @error <> 0 Then ExitLoop         $s_RegRead = RegRead($s_RegKey, $s_RegVal)         If Not (@error) Then             $A_RegVal[$iV][0] = $s_RegVal             $A_RegVal[$iV][1] = $s_RegRead         EndIf         $iV += 1     WEnd     $A_RegVal[0][0] = UBound($A_RegVal) - 1     If $A_RegVal[0][0] >= 1 Then         Return $A_RegVal     Else         Return SetError(3, 3, 0)     EndIf EndFunc   ;==>_RegReadToArray
      i hope you benefit from it
      with my greetings
    • By JackER4565
      Hi, first of all thanks to all the guys who always help people in the forums, I wouldn't be able to do anything if wasn't for your help, even if I don't ask it myself.
       
      I've created this code to get some info on a monitoring network on my work. It relays on _IETableGetCollection and _IETableWriteToArray.
      It works well, but take around 3:25 minutes to get the info from 28 pages (some of them are large and take longer to load, but most of them are small and fast).
      My question is if you see a way to get the program to go faster...
       
      I've tried to make it easy for you to understand and edited somethings with sensitive info.
      (Some of the pages doesn't have the black divider with MIRA in the end, so I need to search if it is there or not.)
       
      #include <IE.au3> #include <array.au3> Local $oIE = _IECreate("about:blank", 0, 0) Local $paginas[28] = [89, 90, 91, 92, 93, 96, 105, 113, 119, 125, 126, 129, 131, 133, 135, 137, 139, 140, 141, 144, 145, 146, 148, 149, 150, 151, 158, 159] Local $Datos_array[0][2] Local $oTable Local $tabla Local $aux_x = 1 Local $ar = 1 Local $Numtables_datos = 0 MsgBox(0, "asd", "asd") For $pag = 0 To UBound($paginas) - 1 Step 1 _IENavigate($oIE, "<WEBSITE URL>" & $paginas[$pag]) ; <<< the pages to load are always the same except for the last digits. _ArrayAdd($Datos_array, $paginas[$pag] & "|" & "Entrante", 0, "|") ; <<<<<<<<<<<<<<<< adds the page number toarray [0, 0] ;############################################ START counts amount of tables with traffic $oTable = _IETableGetCollection($oIE) Local $iNumTables = @extended For $i = 3 To $iNumTables - 2 Step 1 $oTable = _IETableGetCollection($oIE, $i) $nomb_tabla2 = _IETableWriteToArray($oTable) ; <<<<<<<< TABLE TO ARRAY. $string2 = StringStripWS($nomb_tabla2[1][0], 8) If $string2 <> "MIRA" Then $Numtables_datos = $Numtables_datos + 1 Next $tabla_End = $iNumTables - $Numtables_datos ;############################################ FIN $tabla_Start = 4 $tabla_trafico = 2 For $for = 1 To $Numtables_datos Step 1 $oTable = _IETableGetCollection($oIE, $tabla_Start - 1) ; <<<<<<<<<<< NAME OF THE TABLE; row2 = mira $nomb_tabla = _IETableWriteToArray($oTable) ; <<<<<<<< TABLE TO ARRAY ;########################################### ADDS the traffic number into the row $string = StringStripWS($nomb_tabla[1][0], 8) If $string == "MIRA" Then ;si o si pasa por aca 1 vez _ArrayAdd($Datos_array, $nomb_tabla[0][0]) $nomb_aux = $nomb_tabla[0][0] $aux_x = 1 $tabla_trafico = $tabla_trafico + 2 Else ;esto deberia ser por row _ArrayAdd($Datos_array, $nomb_aux & " " & $aux_x) $aux_x = $aux_x + 1 $tabla_trafico = $tabla_trafico + 1 EndIf $oTable = _IETableGetCollection($oIE, $tabla_trafico) Local $aTableData = _IETableWriteToArray($oTable) $bps = _ArrayToString($aTableData, "|", 0, 0, @CRLF, 0, 0) $bps = StringRight($bps, 5) $bps = StringLeft($bps, 4) $trafico_actual = _ArrayToString($aTableData, "|", 0, 0, @CRLF, 2, 2) If $bps == "Gbps" Then $trafico_actual = $trafico_actual * 1000 If $bps == "Kbps" Then $trafico_actual = $trafico_actual / 1000 $Datos_array[$ar][1] = $trafico_actual $ar = $ar + 1 If $string == "MIRA" Then $tabla_Start = $tabla_Start + 2 Else $tabla_Start = $tabla_Start + 1 EndIf Next $ar = $ar + 1 ;~ ############# CAÍDA ############ ;~ If $actual_entrante = 0 Then ;~ $xxx = 0 ;~ Do ;~ MsgBox(0, "Tráfico Caído", $paginas[$i], 5) ;~ $xxx = $xxx + 1 ;~ Until $xxx = 10 ;~ EndIf ;~ ############# CAÍDA ############. Local $Numtables_datos = 0 Next _ArrayDisplay($Datos_array, "Array display") _IEQuit($oIE) Thanks!! 


      monitoria.html
    • By Skysnake
      Hi
      I am trying to set Accelerator keys from an array.
      I select the KEY and CONTROL from a SQLite table, the Array looks like that generated for the Helpfile, but I can't get the CONTROLS to resolve...
      I though about Assign & Eval, but not sure if that's a step in the right direction. IsDeclared shows that the $var exists in Local Scope -1.  
       
      Local $Main = GUICreate("Custom MsgBox", 225, 80) GUICtrlCreateLabel("Please select a button.", 10, 10) Local $idButton_Yes = GUICtrlCreateButton("Yes", 10, 50, 65, 25) Local $idButton_No = GUICtrlCreateButton("No", 80, 50, 65, 25) Local $idButton_Exit = GUICtrlCreateButton("Exit", 150, 50, 65, 25) Local $query, $aResult, $iRows, $iColumns $query = "" ;reset $query = "Select hotkey_key, hotkey_ctrl from mytable where mykeys = 'hotkey' ; " ; ; Query $iRval = _SQLite_GetTable2d($sqliteDb, $query, $aResult, $iRows, $iColumns) If $iRval = $SQLITE_OK Then Local $sizeofHotkeys = UBound($aResult) - 1 ConsoleWrite("$sizeofHotkeys " & $sizeofHotkeys & @CRLF) If $sizeofHotkeys > 0 Then Local $main__aAccelKeys[$sizeofHotkeys][2] For $i = 0 To $sizeofHotkeys - 1 $j = $i + 1 ; replace friendly text with code -- ! alt + Shift ^ Ctrl # Windows $aResult[$j][0] = StringReplace($aResult[$j][0], "Alt", "!") $aResult[$j][0] = StringReplace($aResult[$j][0], "Shift", "+") $aResult[$j][0] = StringReplace($aResult[$j][0], "Ctrl", "^") $main__aAccelKeys[$i][0] = $aResult[$j][0] ;--- $main__aAccelKeys[$i][1] = $aResult[$j][1] ;--- Next ;~ Row|Col 0|Col 1 ;~ Row 0|F2|$idButton_Yes ;~ Row 1|F3|$idButton_No _DebugArrayDisplay($main__aAccelKeys) Local $rv = GUISetAccelerators($main__aAccelKeys, $Main) GUISetState(@SW_SHOW) ; Display the GUI.  
      Please note that this is a modified Helpfile example.
      The Helpfile specifies (a) WinHandle and (b) last Gui created.
      --> the example uses a control not a WinHandle and (b) what happens with ChildGuis? Also, the HelpFile specifies lower case, yet the examples show "{F1}" upper case?
      Also, is there a way to check the result of the GuiSetAccelerator function? 
      Note, if I add these to lines after the FOR loop, then the F1 works, and the DebugArrayDisplays shows control 4... not it's name... So I am in the right place, but my $vars names do not convert to their control numbers in the GUI
      Next $main__aAccelKeys[$sizeofHotkeys - 1][0] = "{F1}" ; -- -- use the extra row for the F1 $main__aAccelKeys[$sizeofHotkeys - 1][1] = $ChmHLP ;--- Skysnake
    • By VIP
      Please help me sort the directory tree by level.
      I want to sort the folders in order: 6-> 5> 4> 3> 2> 1
      Thanks for all the help and suggestions!

      #include <File.au3> #include <Array.au3> Global Const $sRemotePath = '/user/trong/sync' Global Const $sLocalPath = @MyDocumentsDir _Sequential($sLocalPath, $sRemotePath) Func _Sequential($iLocalPath, $iRemotePath) $iLocalPath = StringReplace($iLocalPath, "/", "\") $iRemotePath = StringReplace($iRemotePath, "\", "/") If (StringRight($iLocalPath, 1) = "\") Then $iLocalPath = StringTrimRight($iLocalPath, 1) ConsoleWrite("> From: " & $iLocalPath & @CRLF) ConsoleWrite("> TO: " & $iRemotePath & @CRLF) Local $aDirList = _FileListToArrayRec($iLocalPath, '*', $FLTAR_FOLDERS, $FLTAR_RECUR, $FLTAR_SORT, $FLTAR_FULLPATH) If (Not @error) And IsArray($aDirList) Then For $d = 1 To $aDirList[0] ConsoleWrite("! Current Path (" & $d & '/' & $aDirList[0] & '): ' & $aDirList[$d] & @CRLF) Local $aFileList = _FileListToArray($aDirList[$d], '*', $FLTA_FILES, False) If (Not @error) And IsArray($aFileList) Then For $f = 1 To $aFileList[0] ConsoleWrite("+ File: (" & $f & '/' & $aFileList[0] & ') ON Path ' & $d & '/' & $aDirList[0] & @CRLF) Local $iPathName = StringReplace($aDirList[$d], $iLocalPath & '\', '') Local $iFileName = _SplitPath($aFileList[$f], 5) Local $iRemoteDir = StringReplace($iRemotePath & '/' & $iPathName, '\', '/') Local $iRemoteFile = StringReplace($iRemoteDir & '/' & $iFileName, '\', '/') Local $iLocalFile = $aDirList[$d] & '\' & $iFileName ConsoleWrite("- Path Name : " & $iPathName & @CRLF) ConsoleWrite("- File Name : " & $iFileName & @CRLF) ConsoleWrite("- Remote Dir : " & $iRemoteDir & @CRLF) ConsoleWrite("- Remote File: " & $iRemoteFile & @CRLF) ConsoleWrite("- Local File : " & $iLocalFile & @CRLF) ;~ _FTP_DirCreate($iRemotePath & '\' & $iPathName) ;~ _FTP_ProgressUpload($hFTPSession, $aDirList[$d] & '\' & $iFileName, $iRemotePath & '\' & $iPathName) Next EndIf Next EndIf EndFunc ;==>_Sequential Func _IsFile($sPath) If Not FileExists($sPath) Then Return SetError(1, 0, -1) If StringInStr(FileGetAttrib($sPath), 'D') <> 0 Then Return SetError(0, 0, 0) ;IsDir Else Return SetError(0, 0, 1) ;IsFile EndIf EndFunc ;==>_IsFile Func _SplitPath($sFilePath, $sReturnType = 0) Local $sDrive, $sDir, $sFileName, $sExtension Local $aArray = StringRegExp($sFilePath, "^\h*((?:\\\\\?\\)*(\\\\[^\?\/\\]+|[A-Za-z]:)?(.*[\/\\]\h*)?((?:[^\.\/\\]|(?(?=\.[^\/\\]*\.)\.))*)?([^\/\\]*))$", 1) If @error Then ; This error should never happen. ReDim $aArray[5] $aArray[0] = $sFilePath EndIf $sDrive = $aArray[1] If StringLeft($aArray[2], 1) == "/" Then $sDir = StringRegExpReplace($aArray[2], "\h*[\/\\]+\h*", "\/") Else $sDir = StringRegExpReplace($aArray[2], "\h*[\/\\]+\h*", "\\") EndIf $sFileName = $aArray[3] $sExtension = $aArray[4] If $sReturnType = 0 Then Return $aArray If $sReturnType = 1 Then Return $sDrive If $sReturnType = 2 Then Return $sDir If $sReturnType = 3 Then Return $sFileName If $sReturnType = 4 Then Return $sExtension Local $fName = $sFileName & $sExtension If $sReturnType = 5 Then Return $fName Local $zName = $sDrive & $sDir If $sReturnType = 6 Then Return $zName ; By Dao Van Trong - TRONG.LIVE EndFunc ;==>_SplitPath  
    • By wolflake
      I've used PowerPro for years and it had a feature that let you turn an array into a menu.  It also let you know if it got a right click. I liked the right click feature because it doubled the menu item usage ie left/right on the same menu item.  I tried recreate that usage with a context menu.   With _ArrayToMenu you can pass menu items for 1 and 2 dimensional arrays. Note you can indicate sub-menu but using a -> at the end of the item.  Use a - to make a separater. Optionally you can pass Tooltips by passing a second array. This array must have the same dimensions as the items array even if not all the elements contain tips. The UDF returns an array with this index of row (and if submenus column), the third element is 1 if right clicked otherwise 0 and the fourth element of the array is the label of the menu item. If the user escapes without choosing an item the the first element returns a -1.  Same thing if the user clicks on another window.   @error returns 1 if there was no array passed, 2 if the second array has different dimensions than the first.   If you use the same label in two parts of your menu you will have to distinguish them.  You can do that by additionally making sure that the selection matches the index number(s).  Note that you'll have to match the index number plus label before you match just the label because Switch will use the first match it can find.  In the example below I am using a check on which column the data is in.  If it's not in the first column then it must be the other "Beef".   Beef
      Fruit
      Col2 > Beef
                  Bread   $aR = _ArrayToMenu($aM) Switch $aR[3]
      Case "Beef" and $aR[2] = 0
             Beef1()
       Case "Beef"
             Beef2()
      EndSwitch   On a technical note I attached the context menu to the window itself not a dummy control and I didn't use _GUICtrlMenu_TrackPopupMenu.  Instead I launched the context menu with "send shift-F10" and waited for GuiGetMsg() to give me the selection. Right click is picked up by GUIRegisterMsg WM_RBUTTONUP and Tooltips are done with GUIRegisterMsg WM_MENUSELECT. The whole thing is done with 3 functions. 
      I won't tell you how long it took me to figure this out but I'll say that on one of my early attempts it had two windows running at once and one was just to recieve the right click an tell the other it got it.  Suffice it to say I'm no wiz at Autoit but I really appreciate the support the community offers and I hope someone finds this useful. BTW I wrote a script to produce 1d and 2d auotit array code from excel in case you want to model your menu in excel. Here is the link.
      https://www.autoitscript.com/forum/topic/139260-autoit-snippets/?do=findComment&comment=1412314
      _ArrayToMenu() UDF
      ;ArrayToMenu with submenus, tooltips, rightclick and esc to close. ; #INDEX# ======================================================================================================================= ; Title .........: _ArrayToMenu ; AutoIt Version : 3.3.14.2 ; Description ...: Show an array as a popup menu optionally with tooltips and right click. ; Author(s) .....: Rick Sharp ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name..........: _ArrayToMenu($aArray_menu[,$aArray_tooltips]) ; Description...: Display an array as a menu and return the users choice, display tooltips(optional), return right click. ; Syntax........: _ArrayToMenu($aArray_menu[,$aArray_tooltips]) ; ; Parameters....: ; Required......: A 1d or 2d array of menu items ; Use a minus sign in the item to indicate a menu separator. ; Use -> at the end of an item to indicate a sub-menu. ; Optional......: A 1d or 2d array of tooltips. The array must use the same dimensions as the menu items array. ; ; Return values.: An Array ; $aArray[0] is index of the row (-1 if exited with no choice) ; $aArray[1] is index of the column ; $aArray[2] is 1 if right clicked ; $aArray[3] is the selected item (if any) ; Notes.........: If the user clicks on another window the ArrayToMenu returns as if esc were pressed. ; Sub-Menus are limited to 10 levels if you need more change $ahM[10] ; =============================================================================================================================== ; #VARIABLES# =================================================================================================================== ; Global $__g_iRT = 0, $__g_aTT1, $__g_ahi ; "$__g_iRT" for right click flag, "$__g_aTT1" for tips, "$__g_ahi" for index of id's in menu and tips ; =============================================================================================================================== ; #@error# ====================================================================================================================== ; 1 - First parameter is Not an array ; 2 - The Menu/Items array and the Tips array are not the same number of dimensions ; =============================================================================================================================== #include-once #include <WindowsConstants.au3> #include <GuiMenu.au3> #include <array.au3> #include <misc.au3> Func _ArrayToMenu($aMenu, $att = "") If Not IsArray($aMenu) Then Return SetError(1, 0, -1) Global $__g_iRT = 0 Local $ahM[10], $iCcnt = UBound($aMenu, 2), $iRcnt = UBound($aMenu), $iRow, $iCol, $b_Esc If UBound($aMenu, 2) = 0 Then _ArrayColInsert($aMenu, 1) ;if 1d array make it 2d EndIf ;Prep Loop to make Menus and Sub-Menus $iRcnt = UBound($aMenu) ;Count of Rows/Items $iCcnt = UBound($aMenu, 2) ;Count of Cols/Menus GUIRegisterMsg($WM_RBUTTONUP, "WM_RBUTTONUP") ;handles Right Click If IsArray($att) Then If UBound($att, 2) = 0 Then _ArrayColInsert($att, 1) If UBound($att, 2) <> $iCcnt Or UBound($att) <> $iRcnt Then Return SetError(2, 0, -1) ;$amenu and $att not same dimensions Global $__g_aTT1 = $att ;added $__g_aTT1 because $att was not seen by WM_MenuSelect for tooltips GUIRegisterMsg($WM_MENUSELECT, "WM_MENUSELECT") ;handles tooltips EndIf Local $mPos = MouseGetPos() #Region ### START Koda GUI section ### Form= $hMenu = GUICreate("C_menu", 10, 10, $mPos[0], $mPos[1], $WS_POPUP, $WS_EX_TOPMOST) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### ;Build Menus Global $__g_ahi[$iRcnt + 1][$iCcnt + 1] ;array to hold Menu Item id's $iMcnt = 0 ;Menu count $ahM[$iMcnt] = GUICtrlCreateContextMenu() ;if the array element is null then it falls through and nothing happens For $j = 0 To $iCcnt - 1 ;for each Column/Menu For $i = 0 To $iRcnt - 1 ;for each Row/Item If StringRight($aMenu[$i][$j], 2) = "->" Then ;Sub-Menu $aMenu[$i][$j] = StringTrimRight($aMenu[$i][$j], 2) ;remove -> $iMcnt += 1 $ahM[$iMcnt] = GUICtrlCreateMenu($aMenu[$i][$j], $ahM[$j]) ; $__g_ahi[$i][$j] = $ahM[$iMcnt] ElseIf $aMenu[$i][$j] > "" Then ;Normal item If StringLeft($aMenu[$i][$j], 1) = "-" Then $aMenu[$i][$j] = "" $__g_ahi[$i][$j] = GUICtrlCreateMenuItem($aMenu[$i][$j], $ahM[$j]) EndIf Next Next Send("+{F10}") ;sends right click to open context menu While 1 $nMsg = GUIGetMsg() If $nMsg > 0 Then ;ConsoleWrite("nMsg= " & $nMsg & @CRLF) $iRow = _ArraySearch($__g_ahi, $nMsg) $iCol = _ArraySearch($__g_ahi, $nMsg, 0, 0, 0, 0, 0, $iRow, True) ExitLoop EndIf If _IsPressed("1B") = 1 Or WinActive("C_menu") = 0 Then $b_Esc = -1 ExitLoop EndIf WEnd ;*** Done *** GUIDelete($hMenu) Local $aAr1[4] $aAr1[0] = $iRow $aAr1[1] = $iCol $aAr1[2] = $__g_iRT If Not $b_Esc = -1 Then $aAr1[3] = $aMenu[$aAr1[0]][$aAr1[1]] Else $aAr1[0] = -1 EndIf Return $aAr1 EndFunc ;==>_ArrayToMenu ;Check for Right Click Func WM_RBUTTONUP($hMenu, $iMsg, $iwParam, $ilParam) $__g_iRT = 1 ;Mark as rclicked Send("{Enter}") ;choose the item EndFunc ;==>WM_RBUTTONUP ;Tooltips Func WM_MENUSELECT($hMenu, $iMsg, $iwParam, $ilParam) Local $idMenu = BitAND($iwParam, 0xFFFF) Local $iRow, $iCol If $idMenu > 0 Then $iRow = _ArraySearch($__g_ahi, $idMenu) If $iRow > -1 Then $iCol = _ArraySearch($__g_ahi, $idMenu, 0, 0, 0, 0, 0, $iRow, True) EndIf If $iCol > -1 And $iRow > -1 And $__g_aTT1[$iRow][$iCol] > " " Then ToolTip($__g_aTT1[$iRow][$iCol]) Else ToolTip("") EndIf EndIf EndFunc ;==>WM_MENUSELECT Example 1 Simple 1d array with tooltips, item separator and right click.
      #include "ArrayToMenu.au3" ;Simple 1d array with tooltips item separator and right click. $aM = StringSplit("Zero,One,-,Two/Two_R", ",", 3) ;make an array for the menu items $aT = StringSplit("Zero,One,-,", ",", 3) ;make an array for the menu Tooltips $aR = _ArrayToMenu($aM,$aT) if @error then ConsoleWrite(@error & @CRLF) EndIf ConsoleWrite("R: " & $aR[0] & " " & "C: " & $aR[1] & " " & "Rclick: " & $aR[2] & " " & "Item: " & $aR[3] & @CRLF) If $aR[0] = -1 Then ;either hit escape or clicked on another window ConsoleWrite("Esc" & @CRLF) Exit EndIf ;_ArrayDisplay($aR) Switch $aR[3] Case "Zero" Zero() Case "One" One() Case "Two/Two_R" And $aR[2] = 0 ;No Rclick Two() Case "Two/Two_R" And $aR[2] = 1 ;Rclick Two_R() EndSwitch Func Zero() ConsoleWrite("You chose: Zero" & @CRLF) EndFunc ;==>Zero Func One() ConsoleWrite("You chose: One" & @CRLF) EndFunc ;==>One Func Two() ConsoleWrite("You chose: Two" & @CRLF) EndFunc ;==>Two Func Two_R() ConsoleWrite("You chose: Two_R" & @CRLF) EndFunc ;==>Two_R Example 2 2d array with sub-menu
      #include "ArrayToMenu.au3" ;2d array with a sub-menu dim $aM[4][2] = [["Beef", "Orange"], ["Pork", "Apple"], ["Chicken", "Grape"], ["Fruit->", ""]] ;Note you don't need a tooltip for every item but you at least need a place holder in the array dim $aT[4][2] = [["Red Meat", "Fruit"], ["Other white meat", "Fruit"], ["White meat", "Fruit"], ["", ""]] $aR = _ArrayToMenu($aM,$aT) if @error Then ConsoleWrite(@error & @CRLF) Exit EndIf If $aR[0] = -1 Then ConsoleWrite("Esc" & @CRLF) Exit EndIf ConsoleWrite("R: " & $aR[0] & " " & "C: " & $aR[1] & " " & "Rclick: " & $aR[2] & " " & "Item: " & $aR[3] & @CRLF) Switch $aR[3] Case "Beef" Beef() Case "Pork" Pork() Case "Chicken" Chicken() Case "Orange" ConsoleWrite("Oranges are good for you!" & @CRLF) ConsoleWrite("Oranges" & " $aR[0] = " & $aR[0] & " $aR[1] = " & $aR[1] & @CRLF) Case "Apple" ConsoleWrite("Apples are good for you!" & @CRLF) Case "Grape" ConsoleWrite("Grapes are good for you!" & @CRLF) EndSwitch Func Beef() ConsoleWrite("Beef" & " $aR[0] = " & $aR[0] & " $aR[1] = " & $aR[1] & @CRLF) EndFunc ;==>Beef Func Pork() ConsoleWrite("Pork" & " $aR[0] = " & $aR[0] & " $aR[1] = " & $aR[1] & @CRLF) EndFunc ;==>Pork Func Chicken() ConsoleWrite("Chicken" & @CRLF) EndFunc ;==>Chicken  
×
×
  • Create New...