VIP

[SOLVED] Insert count in the first element on Array

30 posts in this topic

#1 ·  Posted (edited)

Can do without the use of the _ArrayInsert() ? 

#include <Array.au3>
Local $sArray[9] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
;Insert count in the first element 
_ArrayInsert($sArray, 0, UBound($sArray))

For $i = 1 To $sArray[0]
    ConsoleWrite($sArray[$i] & @CRLF)
Next

 

Edited by Trong

Regards,
 

Share this post


Link to post
Share on other sites



J1,

doesn't work:
==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
because you assign 10 elements to a smaller array ;)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Inserting the count in element 0 is bade coding style - though widely used. UBound should be used to retrieve the count of elements (rows, columns).

Global $sArray[9] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
For $i = 0 To UBound($sArray, 1) - 1
    ConsoleWrite($sArray[$i] & @CRLF)
Next

 

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites
Local $sArray[9] = [9, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

Inserting the count in element 0 is bade coding style - though widely used. UBound should be used to retrieve the count of elements (rows, columns).

Global $sArray[9] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
For $i = 0 To UBound($sArray, 1) - 1
    ConsoleWrite($sArray[$i] & @CRLF)
Next

 

 Array already available, I need add/Insert !
Not add from the Array declared.

 

I want to use $sArray[0] , instead of re-using the UBound() to get count.


Regards,
 

Share this post


Link to post
Share on other sites

So where does this phantom array come from?

StringRegExp()

 


Regards,
 

Share this post


Link to post
Share on other sites

When concatenating arrays it is a bad idea to have element 0 as the element count. When adding the second array to the first you have to remove the count from the second array first.
When you have gotten used to UBound you will no longer miss the count in element 0 :)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

BTW: When you have a look at the examples in the help file for StringRegExp you will see they all use UBound.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites


For the best, I'll use UBound()
But asked, so I wanted to know a way to answer my questions.

I tried use ReDim many times but failed .
So I've come up here and ask.


Regards,
 

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Let's assume you already have an array and want to add the result from StringRegExp at the end, then I would use:

#include <Array.au3>
Global $aArray1[9] = [1, 2, 3, 4, 5, 6, 7, 8, 9] 
Global $aArray2 = StringRegExp(...)
_ArrayConcatenate($aArray1, $aArray2)

$aArray1 will then hold the records of both arrays.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

Thanks for all the suggestions! 

I want to code simple and fast so I do not want to use _ArrayInsert: 

Local $sArray[9] = [9, 8, 7, 6, 5, 5, 3, 2, 1]

$sArray = _InsertCountInFirstArray($sArray) ;Insert count in the first element

For $i = 1 To $sArray[0]
    ConsoleWrite($sArray[$i] & @CRLF)
Next

Func _InsertCountInFirstArray($oldArray, $sForce = False)
    If Not IsArray($oldArray) Then Return SetError(1, 0, "")
    Local $sCount = UBound($oldArray)
    If ($oldArray[0] = $sCount - 1) And (Not $sForce) Then Return SetError(0, 1, $oldArray)
    Local $NewArray[$sCount + 1]
    $NewArray[0] = $sCount
    For $i = 1 To $sCount
        $NewArray[$i] = $oldArray[$i - 1]
    Next
    Return $NewArray
EndFunc   ;==>_InsertCountInFirstArray

 

 

Edited by Trong

Regards,
 

Share this post


Link to post
Share on other sites

:whistle:

#include <array.au3>
Local $sArray[9] = [9, 8, 7, 6, 5, 5, 3, 2, 1]
$sArray = StringSplit(_ArrayToString($sArray), "|")
_ArrayDisplay($sArray)

 


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

 That is one other way but I want to be
B) simple and fast:
 

Local $sArray[9] = [9, 8, 7, 6, 5, 5, 3, 2, 1]

$sArray = _InsertCountInFirstArray($sArray) ;Insert count in the first element

For $i = 1 To $sArray[0]
    ConsoleWrite($sArray[$i] & @CRLF)
Next

Func _InsertCountInFirstArray($oldArray, $sForce = False)
    If Not IsArray($oldArray) Then Return SetError(1, 0, "")
    Local $sCount = UBound($oldArray)
    If ($oldArray[0] = $sCount - 1) And (Not $sForce) Then Return SetError(0, 1, $oldArray)
    Local $NewArray[$sCount + 1]
    $NewArray[0] = $sCount
    For $i = 1 To $sCount
        $NewArray[$i] = $oldArray[$i - 1]
    Next
    Return $NewArray
EndFunc   ;==>_InsertCountInFirstArray

 

monkey-selfie-copyright-wikipedia.jpg?w=


Regards,
 

Share this post


Link to post
Share on other sites

I know your problem is solved, but maybe you can modify your regex to add a blank value at the first position of your returned array.

Here is the trick :

#Include <Array.au3>

$string = "This is a string with seven words"

$aWords = StringRegExp($string, "(?|^()|(\w+))", 3)
$aWords[0] = UBound($aWords) - 1
_ArrayDisplay($aWords)

You can note the empty group ^() which captures an empty value once. It's the first value of the returned array, so you can set it to UBound($array) - 1

1 person likes this

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

Your _InsertCountInFirstArray function does what _ArrayInsert does: Move every "row" of the array and then insert. So you are just reinventing the wheel.

That is one other way but I want to be B) simple and fast:

Did you compare the performance of your function vs. _ArrayInsert? Or do you just claim that your function is faster?

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Your _InsertCountInFirstArray function does what _ArrayInsert does: Move every "row" of the array and then insert. So you are just reinventing the wheel.

Did you compare the performance of your function vs. _ArrayInsert? Or do you just claim that your function is faster?

Check it:
File.txt (200MB) Windows 10 x64 | CPU 5300 | SDD

; !_InsertCountInFirstArray WorrkTime:> 20495.6296904569
; !_ArrayInsert WorrkTime: 35828.318692117
#include <Array.au3>

ConsoleWrite("+ Loading data please waiting.... " & @CRLF)
Local $sArray = FileReadToArray("File.txt")
ConsoleWrite("- Processing.... " & @CRLF)

; EG 1
; !_ArrayInsert WorkTime: 46663.5529220402
; !_InsertCountInFirstArray WorkTime:> 0.60849170856201

;~ Local $hTimer = TimerInit()
;~ _ArrayInsert($sArray, 0, UBound($sArray))
;~ Local $fDiff = TimerDiff($hTimer) ;
;~ ConsoleWrite("!_ArrayInsert WorkTime: "& $fDiff &@CRLF)

;~ Local $hTimer2 = TimerInit()
;~ _InsertCountInFirstArray($sArray,0)
;~ Local $fDiff2 = TimerDiff($hTimer2) ;
;~ ConsoleWrite("!_InsertCountInFirstArray WorkTime:> "& $fDiff2 &@CRLF)

; EG2:
; !_InsertCountInFirstArray WorrkTime:> 20495.6296904569
; !_ArrayInsert WorrkTime: 35828.318692117

Local $hTimer2 = TimerInit()
_InsertCountInFirstArray($sArray, 0)
Local $fDiff2 = TimerDiff($hTimer2) ;
ConsoleWrite("!_InsertCountInFirstArray WorkTime:> " & $fDiff2 & @CRLF)

Local $hTimer = TimerInit()
_ArrayInsert($sArray, 0, UBound($sArray))
Local $fDiff = TimerDiff($hTimer) ;
ConsoleWrite("!_ArrayInsert WorkTime: " & $fDiff & @CRLF)

Func _InsertCountInFirstArray($oldArray, $sForce = False)
    If Not IsArray($oldArray) Then Return SetError(1, 0, "")
    Local $sCount = UBound($oldArray)
    If ($oldArray[0] = $sCount - 1) And (Not $sForce) Then Return SetError(0, 1, $oldArray)
    Local $NewArray[$sCount + 1]
    $NewArray[0] = $sCount
    For $i = 1 To $sCount
        $NewArray[$i] = $oldArray[$i - 1]
    Next
    Return $NewArray
EndFunc   ;==>_InsertCountInFirstArray

 


Regards,
 

Share this post


Link to post
Share on other sites
; ===============================================================================================================================
Func _ArrayInsert(ByRef $aArray, $vRange, $vValue = "", $iStart = 0, $sDelim_Item = "|", $sDelim_Row = @CRLF, $iForce = $ARRAYFILL_FORCE_DEFAULT)

    If $vValue = Default Then $vValue = ""
    If $iStart = Default Then $iStart = 0
    If $sDelim_Item = Default Then $sDelim_Item = "|"
    If $sDelim_Row = Default Then $sDelim_Row = @CRLF
    If $iForce = Default Then $iForce = $ARRAYFILL_FORCE_DEFAULT
    If Not IsArray($aArray) Then Return SetError(1, 0, -1)
    Local $iDim_1 = UBound($aArray, $UBOUND_ROWS) - 1
    Local $hDataType = 0
    Switch $iForce
        Case $ARRAYFILL_FORCE_INT
            $hDataType = Int
        Case $ARRAYFILL_FORCE_NUMBER
            $hDataType = Number
        Case $ARRAYFILL_FORCE_PTR
            $hDataType = Ptr
        Case $ARRAYFILL_FORCE_HWND
            $hDataType = Hwnd
        Case $ARRAYFILL_FORCE_STRING
            $hDataType = String
    EndSwitch
    Local $aSplit_1, $aSplit_2
    If IsArray($vRange) Then
        If UBound($vRange, $UBOUND_DIMENSIONS) <> 1 Or UBound($vRange, $UBOUND_ROWS) < 2 Then Return SetError(4, 0, -1)
    Else
        ; Expand range
        Local $iNumber
        $vRange = StringStripWS($vRange, 8)
        $aSplit_1 = StringSplit($vRange, ";")
        $vRange = ""
        For $i = 1 To $aSplit_1[0]
            ; Check for correct range syntax
            If Not StringRegExp($aSplit_1[$i], "^\d+(-\d+)?$") Then Return SetError(3, 0, -1)
            $aSplit_2 = StringSplit($aSplit_1[$i], "-")
            Switch $aSplit_2[0]
                Case 1
                    $vRange &= $aSplit_2[1] & ";"
                Case 2
                    If Number($aSplit_2[2]) >= Number($aSplit_2[1]) Then
                        $iNumber = $aSplit_2[1] - 1
                        Do
                            $iNumber += 1
                            $vRange &= $iNumber & ";"
                        Until $iNumber = $aSplit_2[2]
                    EndIf
            EndSwitch
        Next
        $vRange = StringSplit(StringTrimRight($vRange, 1), ";")
    EndIf
    If $vRange[1] < 0 Or $vRange[$vRange[0]] > $iDim_1 Then Return SetError(5, 0, -1)
    For $i = 2 To $vRange[0]
        If $vRange[$i] < $vRange[$i - 1] Then Return SetError(3, 0, -1)
    Next
    Local $iCopyTo_Index = $iDim_1 + $vRange[0]
    Local $iInsertPoint_Index = $vRange[0]
    ; Get lowest insert point
    Local $iInsert_Index = $vRange[$iInsertPoint_Index]
    ; Insert lines
    Switch UBound($aArray, $UBOUND_DIMENSIONS)
        Case 1
            If $iForce = $ARRAYFILL_FORCE_SINGLEITEM Then
                ReDim $aArray[$iDim_1 + $vRange[0] + 1]
                For $iReadFromIndex = $iDim_1 To 0 Step -1
                    ; Copy existing elements
                    $aArray[$iCopyTo_Index] = $aArray[$iReadFromIndex]
                    ; Move up array
                    $iCopyTo_Index -= 1
                    ; Get next insert point
                    $iInsert_Index = $vRange[$iInsertPoint_Index]
                    While $iReadFromIndex = $iInsert_Index
                        ; Insert new item
                        $aArray[$iCopyTo_Index] = $vValue
                        ; Move up array
                        $iCopyTo_Index -= 1
                        ; Reset insert index
                        $iInsertPoint_Index -= 1
                        If $iInsertPoint_Index < 1 Then ExitLoop 2
                        ; Get next insert point
                        $iInsert_Index = $vRange[$iInsertPoint_Index]
                    WEnd
                Next
                Return $iDim_1 + $vRange[0] + 1
            EndIf
            ReDim $aArray[$iDim_1 + $vRange[0] + 1]
            If IsArray($vValue) Then
                If UBound($vValue, $UBOUND_DIMENSIONS) <> 1 Then Return SetError(5, 0, -1)
                $hDataType = 0
            Else
                Local $aTmp = StringSplit($vValue, $sDelim_Item, $STR_NOCOUNT + $STR_ENTIRESPLIT)
                If UBound($aTmp, $UBOUND_ROWS) = 1 Then
                    $aTmp[0] = $vValue
                    $hDataType = 0
                EndIf
                $vValue = $aTmp
            EndIf
            For $iReadFromIndex = $iDim_1 To 0 Step -1
                ; Copy existing elements
                $aArray[$iCopyTo_Index] = $aArray[$iReadFromIndex]
                ; Move up array
                $iCopyTo_Index -= 1
                ; Get next insert point
                $iInsert_Index = $vRange[$iInsertPoint_Index]
                While $iReadFromIndex = $iInsert_Index
                    ; Insert new item
                    If $iInsertPoint_Index <= UBound($vValue, $UBOUND_ROWS) Then
                        If IsFunc($hDataType) Then
                            $aArray[$iCopyTo_Index] = $hDataType($vValue[$iInsertPoint_Index - 1])
                        Else
                            $aArray[$iCopyTo_Index] = $vValue[$iInsertPoint_Index - 1]
                        EndIf
                    Else
                        $aArray[$iCopyTo_Index] = ""
                    EndIf
                    ; Move up array
                    $iCopyTo_Index -= 1
                    ; Reset insert index
                    $iInsertPoint_Index -= 1
                    If $iInsertPoint_Index = 0 Then ExitLoop 2
                    ; Get next insert point
                    $iInsert_Index = $vRange[$iInsertPoint_Index]
                WEnd
            Next
        Case 2
            Local $iDim_2 = UBound($aArray, $UBOUND_COLUMNS)
            If $iStart < 0 Or $iStart > $iDim_2 - 1 Then Return SetError(6, 0, -1)
            Local $iValDim_1, $iValDim_2
            If IsArray($vValue) Then
                If UBound($vValue, $UBOUND_DIMENSIONS) <> 2 Then Return SetError(7, 0, -1)
                $iValDim_1 = UBound($vValue, $UBOUND_ROWS)
                $iValDim_2 = UBound($vValue, $UBOUND_COLUMNS)
                $hDataType = 0
            Else
                ; Convert string to 2D array
                $aSplit_1 = StringSplit($vValue, $sDelim_Row, $STR_NOCOUNT + $STR_ENTIRESPLIT)
                $iValDim_1 = UBound($aSplit_1, $UBOUND_ROWS)
                StringReplace($aSplit_1[0], $sDelim_Item, "")
                $iValDim_2 = @extended + 1
                Local $aTmp[$iValDim_1][$iValDim_2]
                For $i = 0 To $iValDim_1 - 1
                    $aSplit_2 = StringSplit($aSplit_1[$i], $sDelim_Item, $STR_NOCOUNT + $STR_ENTIRESPLIT)
                    For $j = 0 To $iValDim_2 - 1
                        $aTmp[$i][$j] = $aSplit_2[$j]
                    Next
                Next
                $vValue = $aTmp
            EndIf
            ; Check if too many columns to fit
            If UBound($vValue, $UBOUND_COLUMNS) + $iStart > UBound($aArray, $UBOUND_COLUMNS) Then Return SetError(8, 0, -1)
            ReDim $aArray[$iDim_1 + $vRange[0] + 1][$iDim_2]
            For $iReadFromIndex = $iDim_1 To 0 Step -1
                ; Copy existing elements
                For $j = 0 To $iDim_2 - 1
                    $aArray[$iCopyTo_Index][$j] = $aArray[$iReadFromIndex][$j]
                Next
                ; Move up array
                $iCopyTo_Index -= 1
                ; Get next insert point
                $iInsert_Index = $vRange[$iInsertPoint_Index]
                While $iReadFromIndex = $iInsert_Index
                    ; Insert new item
                    For $j = 0 To $iDim_2 - 1
                        If $j < $iStart Then
                            $aArray[$iCopyTo_Index][$j] = ""
                        ElseIf $j - $iStart > $iValDim_2 - 1 Then
                            $aArray[$iCopyTo_Index][$j] = ""
                        Else
                            If $iInsertPoint_Index - 1 < $iValDim_1 Then
                                If IsFunc($hDataType) Then
                                    $aArray[$iCopyTo_Index][$j] = $hDataType($vValue[$iInsertPoint_Index - 1][$j - $iStart])
                                Else
                                    $aArray[$iCopyTo_Index][$j] = $vValue[$iInsertPoint_Index - 1][$j - $iStart]
                                EndIf
                            Else
                                $aArray[$iCopyTo_Index][$j] = ""
                            EndIf
                        EndIf
                    Next
                    ; Move up array
                    $iCopyTo_Index -= 1
                    ; Reset insert index
                    $iInsertPoint_Index -= 1
                    If $iInsertPoint_Index = 0 Then ExitLoop 2
                    ; Get next insert point
                    $iInsert_Index = $vRange[$iInsertPoint_Index]
                WEnd
            Next
        Case Else
            Return SetError(2, 0, -1)
    EndSwitch

    Return UBound($aArray, $UBOUND_ROWS)
EndFunc   ;==>_ArrayInsert

 


Regards,
 

Share this post


Link to post
Share on other sites

For this case performance is another good reason to use UBound ;)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

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