Jump to content



Recommended Posts

@stealthmsgr Thanks for the :thumbsup:.

It is my wish that the topic be helpful in understanding multidimensional arrays, and I'm also learning new things as I develop this UDF. There is a good tutorial in the Wikipedia about arrays, and there are many helpful members in The General Help and Support Forum who can answer any questions you might have (equally well as I can). If you don't get an answer for a problem there, then I might not know the answer either, but I will always be happy to help if I can.

Edited by czardas
Link to comment
Share on other sites

Thanks so much. As I looked over your UDF I wondered if I could utilize it in my quest. However it may be over-kill. At any rate here's my need. I have a series of updates to be sent out to workstations. I will change the build # of the application at the same time. To keep it simple I just use a text file associated with it. I'm intending to use an INI file to keep track of the version info. What I would like to do is to read in the INI compare it in an array and verify that patch #x is the next patch in sequence and error if not. or at least something to that effect. Well that is my concept. Being as I am new to arrays, I'm in a bit of a sticky patch here. Guidance would be appreciated. Cheers.

In retrospect, I may have inadvertently put  this into the wrong section.  My apologies.

Edited by stealthmsgr
acknowledge possible wrong section.
Link to comment
Share on other sites

13 hours ago, stealthmsgr said:

In retrospect, I may have inadvertently put  this into the wrong section.

:) I'm not fussy about things like that, but it is a general question. There are several ways you could proceed. I tend to use CSV when I need to store the contents of an array in a file. Using INI format may be suitable for your purposes. Both these methods have their drawbacks. Another method could be to use jguinch's UDF: storing the declaration string in a text file - especially useful for numeric data and very easy to use. There are also SQLite database functions you could try, but that's probably overkill.

You don't need to use more than 2 dimensions for this, so the standard Array UDF is quite suitable. This library still needs rigorous testing for very large arrays: it may be better in some circumstances, and worse in others. For example _ArraySortXD() is pretty fast for a 2D arrays with many columns.


Edited by czardas
Link to comment
Share on other sites

Many thanks czardas for the link, info and advice. I would like to have a speedy response in the version checking. As I put this together I'll post some code, although it may be clunky for review. Cheers.

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

Func _Comparever()
Global $avArray1[2]
Global $avArray2[2]

Global $Ver1 = IniRead("C:\Version\Appver_1.ini", "Version", "Ver", "")
Global $Ver2 = IniRead("C:\Version\Appver_2.ini", "Version", "Ver", "")

$avArray1[0] = $Ver1
$avArray2[0] = $Ver2

    $iRet = _ArrayCompare($avArray1, $avArray2)
    If $iRet Then
        MsgBox(0, "", "Array has exactly the same size and values")
        MsgBox(0, "", "Array do not have the same size and values.")

I'm missing something here.

Edited by stealthmsgr
add sample code for review
Link to comment
Share on other sites

  • 3 weeks later...

New Version 0.2.1-beta (see 1st post)

; ==============================================================================================================================
; Changes between versions 0.2.0-beta and 0.2.1-beta
; _ArrayAttach - Added a check for the output array size maximum limit.
; _ShuffleArray - Rewrote the code to be used with the option $iDimension = 0.
; _DeleteRegion - New Function added.
; _ArrayUniqueXD - Replaces the depreciated function _UniqueRegion.
; _ReverseArray - New Function added.
; ==============================================================================================================================

This release includes several improvements on the existing code (some small changes are not mentioned). The biggest change is the renaming of _UniqueRegion() to _ArrayUniqueXD(). Anyone who was using it will have to change the function name in scripts that are affected. Also, tests have been carried out on _ArraySortXD() for up to 16 million elements. Expect more functions, and be aware that some error codes may also change, in the not too distant future.

Now let's peel that spud!

#include 'ArrayWorkshop.au3'

; Delete the outer regions of a cube

Local $aCube = [[['0','1','2','3'],['4','5','6','7'],['8','9','A','B'],['C','D','E','F']], _
                [['G','H','I','J'],['K','X','X','N'],['O','X','X','R'],['S','T','U','V']], _
                [['W','X','Y','Z'],['a','X','X','d'],['e','X','X','h'],['i','j','k','l']], _

Local $aCore = ArrayCore3D($aCube)

; see what remains
ConsoleWrite("The Cube Core" & @LF & @LF)

For $i = 0 To UBound($aCore) -1
    For $j = 0 To UBound($aCore, 2) -1
        For $k = 0 To UBound($aCore, 3) -1
            ConsoleWrite($aCore[$i][$j][$k]) ; should all be X

Func ArrayCore3D($aArray) ; remove the outer elements to reveal the core
    If Not (IsArray($aArray) And UBound($aArray, 0) = 3 And UBound($aArray) > 2 And UBound($aArray, 2) > 2 And UBound($aArray, 3) > 2) Then Return SetError(1)
    _DeleteRegion($aArray, 1) ; delete top ... [example] bounds [4][4][4] ==> [3][4][4]
    _DeleteRegion($aArray, 1, UBound($aArray) -1) ; delete bottom ... [3][4][4] ==> [2][4][4]

    _DeleteRegion($aArray, 2) ; delete left side ... [2][4][4] ==> [2][3][4]
    _DeleteRegion($aArray, 2, UBound($aArray, 2) -1) ; delete right side ... [2][3][4] ==> [2][2][4]

    _DeleteRegion($aArray, 3) ; delete front ... [2][2][4] ==> [2][2][3]
    _DeleteRegion($aArray, 3, UBound($aArray, 3) -1) ; delete back ... [2][2][3] ==> [2][2][2]
    Return $aArray
EndFunc ;==> ArrayCore3D

@iamtheky Above are the bare bones of your Rubix core extraction. With a little modification (extracting each region immediately before deletion) the regions could be reattached to produce the original cube. In this case, a bespoke function should probably manipulate the core directly instead, but the idea is useful for demonstration purposes.

Edited by czardas
Link to comment
Share on other sites

After some consideration, I'm wondering if more functions are actually needed in this library. Inserting or swapping regions can be done with the existing functions already. Does an array ever need to be transposed? I'm still contemplating that last question. Rather than add more functions, perhaps I ought to think more about improvements to functionality with the existing library. The example below demonstrates one method for swapping two regions within a 2D array. The same method could be used to reorder tables in a 3D stack etc...

#include 'ArrayWorkshop.au3'
#include <Array.au3>

; swapping two regions
Local $aArray = [[0,1,2,3,4,5,6,7,8,9], _
_ArrayDisplay($aArray, "before swapping columns")

; swap columns 1, 2, 3 with 6, 7
Local $iDimension = 2, $aNew = _ExtractRegion($aArray, $iDimension) ; start with col 0
_ArrayAttach($aNew, _ExtractRegion($aArray, $iDimension, 6, 2), $iDimension) ; add cols 6, 7
_ArrayAttach($aNew, _ExtractRegion($aArray, $iDimension, 4, 2), $iDimension) ; add cols 4, 5
_ArrayAttach($aNew, _ExtractRegion($aArray, $iDimension, 1, 3), $iDimension) ; add cols 1, 2, 3
_ArrayAttach($aNew, _ExtractRegion($aArray, $iDimension, 8, 2), $iDimension) ; add cols 8, 9
$aArray = $aNew
_ArrayDisplay($aArray, "after swapping columns 1, 2, 3 with 6, 7")

Have I thought of everything? :think: I considered inserting dimensions, because _Predim() only prefixes or appends them, but it's not something I'm ever likely to use.

Edited by czardas
Link to comment
Share on other sites

I at one point in time thought i was good with arrays, i was wrong.  You are to arrays what @UEZ is to gdi+

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

Link to comment
Share on other sites

On 4/9/2016 at 0:52 PM, czardas said:

Does an array ever need to be transposed?

@czardas The answer is no, although I was just being lazy. It's still a very useful thing to have. I actually thought it would be more complicated, but it turned out to be one of the easiest functions to write. I kind of got excited so I'm posting it here for now (I'll add it to the next update in a few days time).

With two-dimensional arrays, _ArrayTransform() behaves exactly the same as _ArrayTranspose(); because only one transformation is actually possible. With more dimensions, you can reshape the array in a variety of ways. Basically the bounds of each dimension are swapped and the array filled accordingly [see comments in the function header]. A couple of tests appear below the function. Thanks again to @jchd for suggesting some invaluable ideas which really got me thinking.

#include <Array.au3>
#include 'ArrayWorkshop.au3'

; #FUNCTION# ===================================================================================================================
; Name...........: _ArrayTransform
; Description ...: Alters the shape of a multidimensional array without losing data.
; Syntax.........: _ArrayTransform($aArray [, $sShape = Default])
; Parameters.....; $aArray - The array to modify.
;                  $sShape - [Optional] String or integer value - output dimension bounds sequence [See Comments]
; Return values .: Success - Returns the transformed array [ByRef].
;                  Failure sets @error as follows:
;                  |@error = 1 The 1st parameter is not a valid array.
;                  |@error = 2 The 1st parameter does not contain any elements.
;                  |@error = 3 Bad $sShape parameter.
; Author ........: czardas
; Comments ......: The shape parameter must be a sequence of unique digits: each refering to a different dimension.
;                  For a 2D array the default shape parameter is '21', and for 3D it is '321' etc...
;                  The default output sequence transposes the array by reversing the dimension bounds ==> [7][8] becomes [8][7].
;                  If you want a different output shape, change the dimension bounds sequence.
;                  eg. when $sShape = '2431', [1][2][3][4] will become [2][4][3][1]
;                  This function is limited to arrays of between two and nine dimensions.
; ==============================================================================================================================
Func _ArrayTransform(ByRef $aArray, $sShape = Default) ; [default shape = reverse sequence '987654321']
    If Not IsArray($aArray) Or UBound($aArray, 0) > 9 Then Return SetError(1) ; not a valid array.

    Local $aBound = __GetBounds($aArray)
    If @error Or $aBound[0] = 1 Then Return SetError(2)
    If $sShape = Default Then $sShape = StringRight('987654321', $aBound[0])
    If StringLen($sShape) <> $aBound[0] Or Not StringIsDigit($sShape) Then Return SetError(3)

    Local $aTrac = StringSplit($sShape, ''), $sTransfer = '$aSource'
    For $i = 1 To $aBound[0]
        If $aTrac[$i] > $aBound[0] Or StringInStr($sShape, $aTrac[$i], 0, 2) Then Return SetError(3) ; bad $sShape parameter [dimensions must already exist]
        $sTransfer &= '[$a[' & $aTrac[$i] & ']]' ; default ==> '$aSource[$a[9]][$a[8]][$a[7]][$a[6]][$a[5]] etc...'

    Local $aBoundNew = $aBound
    __SwapSequence1D($aBoundNew, $aTrac, 1, $aBoundNew[0])

    Local $aNewArray = ___NewArray($aBoundNew), $fnFloodFill = __FloodFunc()[$aBound[0]]

    For $i = 1 To $aBoundNew[0]
        $aBoundNew[$i] -= 1
    $fnFloodFill($aNewArray, $aBoundNew, 0, 0, '', $aArray, $sTransfer)
    $aArray = $aNewArray
EndFunc ;==> _ArrayTransform

#Region - tests
Local $aArray[4][3] = [[0,1,2],[3,4,5],[6,7,8],[9,'a','']]
_ArrayDisplay($aArray, 'Before transformation.')

; Test 2D
_ArrayDisplay($aArray, 'It works!')

; test 3D
_Predim($aArray, 3, True) ; prefix another dimension to test 3D
_ArrayTransform($aArray, 132) ; [3D] leave the first dimension in place
_Predim($aArray, 2, True) ; remove the first dimension we added earlier
_ArrayDisplay($aArray, '3D also works.') ; now we are back to the original array


Edited by czardas
Link to comment
Share on other sites

I rarely have any idea: all I do is peddle some good ideas of others.

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

Here's another (practical rather than exciting) example which uses this UDF. I've made several similar functions to this before but never been 100% satisfied. This date sort function will not become part of the ArrayWorkshop library: it's just an experiment and an example of a function which makes use of ArrayWorkshop. The same function could quite easily have been written using the standard array UDF.

Suppose you download some statistics in a csv and want to sort the data on a date column. The dates may be formatted in a variety of ways. A common solution to this problem is to corrupt the original information in order to comply with the programmer's expectations. IMO the vernacular tradition should be embraced as much as possible so that normal people can type whatever they want. So once again I present you with yet another imperfect solution (intended for 1D or 2D arrays only).

You can set this function to sort US date format (or 'other'). If the format parameter is not recognized (either 'UK' or 'US'), then the dates are treated as being formatted in the logical sequence - year - month - day. It's slightly fuzzy: as one would expect from a function like this! 

#include <Array.au3>
#include 'ArrayWorkshop.au3'

Local $aRecords = [ _
['Date','Details','Amount'], _
['Wed | 10-2-16 ???','ebay','1.00'], _
['Wed = 1 / 1 / 16','advert','17.87'], _
['Sun | 8-11-15','insurance','13.05'], _
['Tue | 22-9-15','hosting','70.34'], _
['junk-12-21-21-21','ignore','N/A'], _
['Mon - 4, 4. 16','transport','117.00'], _
['Sat - 19-03-16','registration','11.00'], _
['Wed - 01-01-16','power','65.21'], _
['Sat - 07-11-2015','advert','12.90']]

SortByDate($aRecords, 'UK', 1)

Func SortByDate(ByRef $aArray, $sFormat = 'UK', $iStart = 0, $iEnd = -1, $iCol = 0)
    ; Strips any non-numeric characters from the start or end of the string.
    ; Tries to identify a date which includes the delimiters -,./\ or space.
    ; Delimiters may also be padded by a single space character on the left and/or the right. [max = 3 chars]

    If Not IsArray($aArray) Or UBound($aArray, 0) > 2 Or UBound($aArray) = 0 Then Return SetError(1) ; $aArray is not valid
    If $sFormat = Default Then $sFormat = 'UK' ; change the Default format to US if you like [requires two edits]
    Local $iDay, $iMon, $iYear = 4
    Switch $sFormat
        Case 'UK' ; day, month, year
            $iDay = 0
            $iMon = 2
        Case 'US' ; month, day, year
            $iDay = 2
            $iMon = 0
        Case Else ; year, month, day
            $iDay = 4
            $iMon = 2
            $iYear = 0

    $iStart = ($iStart = Default) ? 0 : Int($iStart)
    Local $iBound = UBound($aArray)
    $iEnd = ($iEnd = Default Or $iEnd = -1) ? $iBound -1 : Int($iEnd)
    If $iEnd < 1 Or $iEnd >= $iBound Then Return SetError(3) ; bad $iEnd parameter
    If $iStart < 0 Or $iStart >= $iEnd Then Return SetError(2) ; bad $iStart parameter

    Local $iNewIdx, $b2D = UBound($aArray, 0) = 2 ? True : False
    If $b2D Then
        $iNewIdx = UBound($aArray, 2) ; new column to sort on
        If $iNewIdx = 0 Then Return SetError(1) ; $aArray is not valid
        $iCol = ($iCol = Default) ? 0 : Int($iCol)
        $iNewIdx = 1 ; new column to sort on
        $iCol = 0
        _Predim($aArray, 2)
    If $iCol >= $iNewIdx Or $iCol < 0 Then Return SetError(4) ; bad $iCol parameter
    ReDim $aArray[$iBound][$iNewIdx +1]

    Local $sTemp, $aRegExp, $sCentury = StringLeft(@YEAR, 2)
    For $i = $iStart To $iEnd
        $sTemp = StringRegExpReplace($aArray[$i][$iCol], '(?i)(\A\D*)(?U)(.*)(\D*\z)', '$2') ; try to identify a date [\D* strips leading/trailing non-numeric garbage]
        $aRegExp = StringRegExp($sTemp, '[\d]+|( ?[ ,/\Q.-\\E]\ ?)', 3) ; attempt to split the cropped result
        If IsArray($aRegExp) And UBound($aRegExp) = 5 And StringLen($aRegExp[$iDay]) < 3 And StringLen($aRegExp[$iMon]) < 3 And StringLen($aRegExp[$iYear]) < 5 Then
            If StringLen($aRegExp[$iYear]) = 2 Then $aRegExp[$iYear] = $sCentury & $aRegExp[$iYear] ; two digit years default to the current century
            $aArray[$i][$iNewIdx] = StringFormat("%04i%02i%02i", $aRegExp[$iYear], $aRegExp[$iMon], $aRegExp[$iDay]) ; add each formatted date to the temporary column
            $aArray[$i][$iNewIdx] = 'z' & StringFormat('%08i', $i) ; non-matching values get dumped at the end
    _ArraySortXD($aArray, 1, 0, $iEnd, $iStart, $iNewIdx) ; dim = 1, algo = 0, end = -1, row = 0, col = final column

    If $b2D Then
        ReDim $aArray [$iBound][$iNewIdx] ; delete the temporary column
        _PreDim($aArray, 1) ; delete the temporary dimension
EndFunc ;==> SortByDate

One would expect the dates in the date column to be of a consistent format, but the function doesn't care about this, nor whether a date is genuine. It is assumed that these concerns have already been addressed at the time of data entry. This is about as wide as I am prepared to cast the net because this function is designed to embrace the most common numeric based (date) formats used by people throughout the world (not necessarily formats generated, or recognized, by computer programs).

Work on ArrayWorkshop.au3 will resume shortly. :)

Edited by czardas
Link to comment
Share on other sites

  • 2 weeks later...

Update version 0.2.2-beta in the first post.

; Changes between versions 0.2.1-beta and 0.2.2-beta
; _ArrayTransform - New Function added.
; _InsertRegion - New Function added.
; _SearchArray - New parameter added - optional search algorithm for typical string matching criteria.
;  AU3Stripper - Added directive for AU3Stripper to ignore ArrayWorkshop altogether - a necessary precaution with AU3Stripper.

Earlier versions were not compatible with AU3Stripper for various reasons. Nearly all functions rely on executed string instructions which are not visible. Until a full analysis of all affected areas has been done, the whole script has been protected. You can still use AU3Stripper. Any extra bloat has to be put into perspective: considering the thousands of lines of code that would have been required to produce this library without using remote loops and hidden function calls. :think: It's no big deal. ;)

Edited by czardas
Link to comment
Share on other sites

Due to a leak in an error check for _ArrayTransform() in version 0.2,2, I have decided to release this update slightly ahead of schedule.

; Changes between versions 0.2.2-beta and 0.2.3-beta
; _ArrayTransform - Fixed leak in error check for bad shape parameter. [corrections also made to documentation]
; _ArrayUniqueXD - Implemented scripting dictionary: to generate unique keys.
; _ArraySortXD - Algorithm 256 now accepts numeric strings with leading/trailing whitespaces, includes WS after the sign symbol.

After further analysis, and for reasons mentioned earlier, I have decided to create a tool to generate stripped down (and compressed) versions of this UDF to meet individual requirements. Several other example scripts are also affected by similar problems. Always test compiled scripts fully before release.

Edited by czardas
Link to comment
Share on other sites

  • 3 weeks later...

First Stable Release [see 1st post]

; ==============================================================================================================================
; Changes between versions 0.2.3-beta and 1.0.0 [1st stable release]
; _ShuffleArray - Removed the dependency on _ArrayFlatten. [optimization for fruit-machine style]
; _ArrayUniqueXD - Increased the maximum number of dimensions to 9 [heaven knows idea why]
; __TagSortSwap - Renamed internal function. [Original name ==> __SwapSequence1D]
; __TagSortSwapXD - Renamed internal function. [Original name ==> __SwapSequence2D]
; ___Search1D - Modifications to reduce bloat. [internal function]
; _ArrayFlatten - Depreciated function. [Removed]
; __CountElements - Depreciated internal function. [Removed]
; ___Read1D - Depreciated internal function. [Removed]
; ==============================================================================================================================

When I started writing this UDF I really just wanted to have support for up to 3, and perhaps 4, dimensions for standard array functions. With several future projects in mind, I increased the number of dimensions to 9, gradually modifying the approach as I tried different methods. One of the targets I set myself was a limit of 2000 lines of code - including documentation. Admittedly I wandered down some well trodden paths, but that's all part and parcel of the learning curve.

_ArrayFlatten() was originally introduced as a helper function for _ShuffleArray(). This currently depreciated function was neither sophisticated nor discerning about how the array became one dimensional, providing the amount of data was preserved: exact data location didn't matter.


#include 'ArrayWorkshop.au3' ; needed for __GetBounds()

; #FUNCTION# ===================================================================================================================
; Name...........: _ArrayFlatten
; Description ...: Turns a multidimensional array into a one dimensional array while maintaining all the data.
; Syntax.........: _ArrayFlatten($aArray)
; Parameters.....; $aArray - The original array.
; Return values .: Returns the modified array ByRef.
;                  Failure sets @error as follows:
;                  |@error = 1 The parameter is not a valid array.
;                  |@error = 2 Dimension limit exceeded.
;                  |@error = 3 Arrays must contain at least one element.
; Author.........: czardas
; Comments ......; This function works for up to 9 dimensions.
; ==============================================================================================================================
Func _ArrayFlatten(ByRef $aArray) ; <== DO NOT RENAME
    If Not IsArray($aArray) Then Return SetError(1)

    Local $aBound = __GetBounds($aArray, 9)
    If @error Then Return SetError(3) ; $aArray must contain at least one element

    If $aBound[0] > 9 Then Return SetError(2)
    If $aBound[0] = 1 Then Return ; array is already one dimensional

    For $i = 1 To 9
        $aBound[$i] = ($i > $aBound[0]) ? 0 : $aBound[$i] - 1

    Local $aTarget[__CountElements($aArray)], $iCount = 0, _
            $sExpression = '$aArray' & StringLeft('[$1][$2][$3][$4][$5][$6][$7][$8][$9]', $aBound[0] * 4)

    For $9 = 0 To $aBound[9]
        For $8 = 0 To $aBound[8]
            For $7 = 0 To $aBound[7]
                For $6 = 0 To $aBound[6]
                    For $5 = 0 To $aBound[5]
                        For $4 = 0 To $aBound[4]
                            For $3 = 0 To $aBound[3]
                                For $2 = 0 To $aBound[2]
                                    For $1 = 0 To $aBound[1]
                                        $aTarget[$iCount] = Execute($sExpression)
                                        $iCount += 1

    $aArray = $aTarget
EndFunc    ;==>_ArrayFlatten

; #INTERNAL_USE_ONLY# ==========================================================================================================
; Description ...: Return the total number of elements contained within a multidimensional array.
; ==============================================================================================================================
Func __CountElements($aArray)
    Local $iCount = 1
    For $i = 1 To UBound($aArray, 0)
        $iCount *= UBound($aArray, $i)
    Return $iCount
EndFunc    ;==>__CountElements

As far as building a stripper for ArrayWorkshop.au3 is concerned, it will have to wait a little while longer because I have a big work load - as usual. :mellow: In the mean while, anyone brave enough to have a go themselves can try these suggestions:

1. DO NOT remove the directives #Au3Stripper_Off or #Au3Stripper_On.
2. Remove unused functions and unused dependencies [see the table below].
3. Remove 'remote-loop' code and parameters from unused (higher) dimensions, but leave all nine ___FloodXD function names alone.
4. Don't try and rename anything. :whistle:

; Dependency Tree for each function (including interdependencies)
; _ArrayAttach     __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, ___NewArray, __ResetBounds, _PreDim
; _ArraySortXD     __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, ___NewArray, __Separate1D,__QuickSort1D, __CreateTrac, __Separate256, __QuickSortXD,
;                  __SeparateXD, ___Reverse1D, __TagSortSwap, __ExtractVector, __TagSortSwapXD, __AcquireExponent, ___FormatNum, ___NumCompare
; _ArrayTransform  __GetBounds, __FloodFunc, ___FloodXD, ___NewArray, __TagSortSwap
; _ArrayUniqueXD   __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, __ResetBounds
; _DeleteDimension __GetBounds, __FloodFunc, ___FloodXD, ___NewArray
; _DeleteRegion    __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, __ResetBounds
; _ExtractRegion   __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, ___NewArray
; _InsertRegion    __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, ___NewArray, __ResetBounds, _ArrayAttach, _ExtractRegion, _PreDim
; _PreDim          __GetBounds, __FloodFunc, ___FloodXD, ___NewArray
; _ReverseArray    __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices,___NewArray, ___Reverse1D
; _SearchArray     __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, __ResetBounds, ___Search1D, __FindExact, __FindString, __FindWord,
;                  __FindExactCase, __FindStringCase, __FindWordCase, $g__ARRWSHOP_RESUME, $g__ARRWSHOP_SUB
; _ShuffleArray    __GetBounds, __FloodFunc, ___FloodXD, __HiddenIndices, ___NewArray, __Shuffle1D, __ShuffleXD

As an example here is the code needed if you only want to include _ArrayTransform() for three dimensions.


Func _ArrayTransform(ByRef $aArray, $sShape = Default) ; [default shape = reverse sequence '987654321']
    If Not IsArray($aArray) Then Return SetError(1) ; not a valid array.

    Local $aBound = __GetBounds($aArray)
    If @error Or $aBound[0] = 1 Or $aBound[0] > 9 Then Return SetError(1)
    If $sShape = Default Then $sShape = StringRight('987654321', $aBound[0])
    If StringLen($sShape) <> $aBound[0] Or Not StringIsDigit($sShape) Then Return SetError(2) ; bad $sShape parameter

    Local $aTrac = StringSplit($sShape, ''), $sTransfer = '$aSource'
    For $i = 1 To $aBound[0]
        If Not StringInStr($sShape, $i) Then Return SetError(2) ; bad $sShape parameter [dimensions must already exist]
        $sTransfer &= '[$a[' & $aTrac[$i] & ']]' ; default ==> '$aSource[$a[9]][$a[8]][$a[7]][$a[6]][$a[5]] etc...'

    Local $aBoundNew = $aBound
    __TagSortSwap($aBoundNew, $aTrac, 1, $aBoundNew[0])

    Local $aNewArray = ___NewArray($aBoundNew), $fnFloodFill = __FloodFunc()[$aBound[0]]

    For $i = 1 To $aBoundNew[0]
        $aBoundNew[$i] -= 1
    $fnFloodFill($aNewArray, $aBoundNew, 0, 0, '', $aArray, $sTransfer)
    $aArray = $aNewArray
EndFunc    ;==>_ArrayTransform

Func __GetBounds($aArray, $iHypothetical = 0)
    Local $iMaxDim = UBound($aArray, 0)
    Local $aBound[($iHypothetical ? $iHypothetical : $iMaxDim) + 1] ; [or ==> Local $aBound[9]]
    $aBound[0] = $iMaxDim
    For $i = 1 To $iMaxDim
        $aBound[$i] = UBound($aArray, $i)
        If $aBound[$i] = 0 Then Return SetError(1)
    If $iHypothetical Then
        For $i = $iMaxDim + 1 To $iHypothetical
            $aBound[$i] = 1 ; imaginary dimensions
    Return $aBound
EndFunc    ;==>__GetBounds

Func __FloodFunc()
    Local $aFloodFunc = ['', ___Flood1D, ___Flood2D, ___Flood3D, ___Flood4D, ___Flood5D, ___Flood6D, ___Flood7D, ___Flood8D, ___Flood9D]
    Return $aFloodFunc
EndFunc    ;==>__FloodFunc

Func ___NewArray($aBound)
    Switch $aBound[0]
        Case 1
            Local $aArray[$aBound[1]]
        Case 2
            Local $aArray[$aBound[1]][$aBound[2]]
        Case 3
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]]
        Case 4
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]]
        Case 5
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]][$aBound[5]]
        Case 6
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]][$aBound[5]][$aBound[6]]
        Case 7
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]][$aBound[5]][$aBound[6]][$aBound[7]]
        Case 8
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]][$aBound[5]][$aBound[6]][$aBound[7]][$aBound[8]]
        Case 9
            Local $aArray[$aBound[1]][$aBound[2]][$aBound[3]][$aBound[4]][$aBound[5]][$aBound[6]][$aBound[7]][$aBound[8]][$aBound[9]]
    Return $aArray
EndFunc    ;==>___NewArray

Func __TagSortSwap(ByRef $aArray, ByRef $aTrac, $iStart, $iEnd)
    Local $vFirst, $i, $iNext

    For $iInit = $iStart To $iEnd ; initialize each swap sequence
        If $aTrac[$iInit] <> $iInit Then ; elements will now be swapped in a sequence
            $i = $iInit ; set the current index to the start of the sequence
            $vFirst = $aArray[$i] ; copy data [although we don't know where to put it yet]

                $aArray[$i] = $aArray[$aTrac[$i]] ; overwrite each element in the sequence
                $iNext = $aTrac[$i] ; get the next index in the sequence
                $aTrac[$i] = $i ; set to ignore overwritten elements on subsequent encounters
                $i = $iNext ; follow the trail as far as it goes [index could be higher or lower]
            Until $aTrac[$i] = $iInit ; all sequences end at this juncture

            $aArray[$i] = $vFirst ; now we know where to put the initial element we copied earlier
            $aTrac[$i] = $i ; set to ignore on subsequent encounters [as above]
EndFunc    ;==>__TagSortSwap

Func ___Flood1D(ByRef $aTarget, $aBound, $iDimension, $iSubIndex, $iFrom, $aSource, $sTransfer) ; [still experimental]
    #forceref $iDimension, $iFrom, $aSource ; $iDimension would normally not apply here (special case)
    Local $a[10] = ['', 0, 0, 0, 0, 0, 0, 0, 0, 0] ; loop iteration count [or indices of higher dimensions within the source array]
    For $a[1] = $iSubIndex To $aBound[1] ; from the start to the bounds of the 1st dimension (special case)
        ; only one operation is needed in this special case
        $aTarget[$a[1]] = Execute($sTransfer) ; hidden parameters may appear in the code being executed
EndFunc    ;==>___Flood1D

Func ___Flood2D(ByRef $aTarget, $aBound, $iDimension, $iSubIndex, $iFrom, $aSource, $sTransfer)
    #forceref $iFrom, $aSource ; hidden parameters
    Local $a[10] = ['', 0, 0, 0, 0, 0, 0, 0, 0, 0] ; loop iteration count [or indices of higher dimensions within the source array]
    For $a[2] = 0 To $aBound[2]
        For $a[1] = 0 To $aBound[1]
            $a[$iDimension] = $iSubIndex ; override the iteration count (fast method) - $a[0] has no influence
            $aTarget[$a[1]][$a[2]] = Execute($sTransfer) ; hidden parameters may appear in the code being executed
EndFunc    ;==>___Flood2D

Func ___Flood3D(ByRef $aTarget, $aBound, $iDimension, $iSubIndex, $iFrom, $aSource, $sTransfer)
    #forceref $iFrom, $aSource ; as above
    Local $a[10] = ['', 0, 0, 0, 0, 0, 0, 0, 0, 0] ; as above
    For $a[3] = 0 To $aBound[3]
        For $a[2] = 0 To $aBound[2]
            For $a[1] = 0 To $aBound[1]
                $a[$iDimension] = $iSubIndex ; as above
                $aTarget[$a[1]][$a[2]][$a[3]] = Execute($sTransfer) ; as above
EndFunc    ;==>___Flood3D

Func ___Flood4D()
EndFunc    ;==>___Flood4D

Func ___Flood5D()
EndFunc    ;==>___Flood5D

Func ___Flood6D()
EndFunc    ;==>___Flood6D

Func ___Flood7D()
EndFunc    ;==>___Flood7D

Func ___Flood8D()
EndFunc    ;==>___Flood8D

Func ___Flood9D()
EndFunc    ;==>___Flood9D


More modifications can be made to the example above, but I advise caution against doing so. Removing unused parts of the remote-loop code (as shown above) should be safe, providing that you fully test everything is working before compiling the script. Other code modifications cannot be guaranteed to work in every situation. I think the amount of bloat is reasonable, even without any attempt to strip it down. Bear in mind that any changes you make are at your own risk. Any questions about this, feel free to ask.

Edited by czardas
Link to comment
Share on other sites

I just spotted a bug affecting _ArrayUniqueXD(), introduced in the last updated version. I doubt anyone using the function will have noticed a problem, but it's only a matter of time before such circumstances occur. I have updated the first post to version 1.0.1 (minimal changes).

; ==============================================================================================================================
; Changes between versions 1.0.0 and 1.0.1
; _ArrayUniqueXD - Bug introduced in version 1.00 [line 447] ExitLoop 5 should have been changed to ExitLoop 9.
; ==============================================================================================================================


Edited by czardas
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

  • Create New...