Jump to content
guinness

_ArrayFilter, _ArrayMap and _ArrayReduce, by passing a function reference i.e. a function callback

Recommended Posts

guinness

Just trying out the latest version of AutoIt and thinking more functional

#include <Array.au3>

; Example
; An example of filtering, mapping and reducing arrays, using a function reference.
; This is similiar to how it would be done in the likes of JavaScript
; i.e. more functional (declarative) than procedural (imperative)

; Filter example
Local $aiFilteredBefore[] = [1, 2, 3, 50, 30, 40, 20, 30]
Local $aiFilteredAfter = _ArrayFilter($aiFilteredBefore, GtrThan30)
_ArrayDisplay($aiFilteredAfter, '_ArrayFilter::')

; Map example
Local $aiMappedBefore[] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Local $aiMappedAfter = _ArrayMap($aiMappedBefore, MultiplyByTwo)
_ArrayDisplay($aiMappedAfter, '_ArrayMap::')

; Reduce example
; Sum all values in the array
Local $aiReducedBefore[] = [1, 2, 3, 50, 30, 40, 20, 30]
ConsoleWrite('_ArrayReduce:: ' & _ArrayReduce($aiReducedBefore, SumValues) & @CRLF)

; Passing an empty array, will return the initial value; otherwise, sets @error to 4
; if no initial value is defined
Local $aEmpty[] = []
ConsoleWrite('_ArrayReduce:: ' & _ArrayReduce($aEmpty, SumValues, 0) & @CRLF)

; Array callback functions (for the examples only)

Func GtrThan30($iValue)
    Return $iValue > 30
EndFunc   ;==>GtrThan30

Func MultiplyByTwo($iValue, $iIndex, $aiArray)
    ; Notice how the function is called with the optional arguments "index" and "original array"
    ConsoleWrite('Index:: ' & $iIndex & ', Array:: ' & _ArrayToString($aiArray) & @CRLF)
    Return $iValue * 2
EndFunc   ;==>MultiplyByTwo

Func SumValues($a, $b)
    Return $a + $b
EndFunc   ;==>SumValues

; Functions

; The callback function is invoked with fn(value, [index, [array]])
Func _ArrayFilter($avArray, $hFunc)
    If Not IsArray($avArray) Then
        ; Null is more appropriate than returning the likes of -1 or an empty array
        Return SetError(1, 0, Null)
    EndIf

    If Not IsFunc($hFunc) Then
        Return SetError(2, 0, Null)
    EndIf

    Local Const $iLength = UBound($avArray)
    Local $avFiltered[$iLength]
    If $iLength = 0 Then
        Return $avFiltered
    EndIf

    Local $iIndex = 0
    For $i = 0 To $iLength - 1
        Local $bIsFiltered = __ArrayCall($hFunc, 3, $avArray[$i], $i, $avArray)
        If @error Then
            Return SetError(@error, @extended, Null)
        ElseIf $bIsFiltered Then
            $avFiltered[$iIndex] = $avArray[$i]
            $iIndex += 1
        EndIf
    Next

    ReDim $avFiltered[$iIndex]

    Return $avFiltered
EndFunc   ;==>_ArrayFilter

; The callback function is invoked with fn(value, [index, [array]])
Func _ArrayMap($avArray, $hFunc)
    If Not IsArray($avArray) Then
        ; Null is more appropriate than returning the likes of -1 or an empty array
        Return SetError(1, 0, Null)
    EndIf

    If Not IsFunc($hFunc) Then
        Return SetError(2, 0, Null)
    EndIf

    Local Const $iLength = UBound($avArray)
    Local $avMapped[$iLength]
    If $iLength = 0 Then
        Return $avMapped
    EndIf

    For $i = 0 To $iLength - 1
        $avMapped[$i] = __ArrayCall($hFunc, 3, $avArray[$i], $i, $avArray)
        If @error Then
            Return SetError(@error, @extended, Null)
        EndIf
    Next

    Return $avMapped
EndFunc   ;==>_ArrayMap

; The callback function is invoked with fn(current, value, [index, [array]])
Func _ArrayReduce($avArray, $hFunc, $vInitial = Default)
    If Not IsArray($avArray) Then
        ; Null is more appropriate than returning the likes of -1 or an empty array
        Return SetError(1, 0, Null)
    EndIf

    If Not IsFunc($hFunc) Then
        Return SetError(2, 0, Null)
    EndIf

    Local $bHasInitial = @NumParams >= 3
    Local $iLength = UBound($avArray)
    If $iLength = 0 Then
        If Not $bHasInitial Then
            Return SetError(4, 0, Null)
        EndIf

        Return $vInitial
    EndIf

    For $i = 0 To $iLength - 1
        If $bHasInitial Then
            $vInitial = __ArrayCall($hFunc, 3, $vInitial, $avArray[$i], $i, $avArray)
            If @error Then
                Return SetError(@error, @extended, Null)
            EndIf
        Else
            $bHasInitial = True
            $vInitial = $avArray[$i]
        EndIf
    Next

    Return $vInitial
EndFunc   ;==>_ArrayReduce

Func __ArrayCall($hFunc, $iError, $vArg1 = Default, $vArg2 = Default, $vArg3 = Default, $vArg4 = Default)
    Local Const $CALL_ERROR = 0xDEAD
    Local Const $CALL_EXTENDED = 0xBEEF

    Local $vRet = Call($hFunc, $vArg1)
    If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then
        $vRet = Call($hFunc, $vArg1, $vArg2)
        If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then
            $vRet = Call($hFunc, $vArg1, $vArg2, $vArg3)
            If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then
                $vRet = Call($hFunc, $vArg1, $vArg2, $vArg3, $vArg4)
                If @error = $CALL_ERROR And @extended = $CALL_EXTENDED Then
                    ; The function exists, but there is no appropriate function signature
                    Return SetError($iError, 0, Null)
                EndIf
            EndIf
        EndIf
    EndIf

    Return SetError(@error, @extended, $vRet)
EndFunc   ;==>__ArrayCall

 

Edited by guinness
  • Like 1

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Share this post


Link to post
Share on other sites
guinness

I have updated the first post with:

  • Added _ArrayMap()
  • Callback functions now provide also the original array (similar to JavaScript)
  • Tidied code based on the style guide
  • Fixed bug in _ArrayFilter(), where the filtered array caused an "out of bounds" error
  • Like 1

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

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

    • Chimp
      By Chimp
      An example on how to inject jQuery into a web page
      It can be useful to manage the page from AutoIt using jQuery.
      Idea from here: http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet
      Suggestions and improvements are welcome
      #include <ie.au3> Example() Func Example() Local $oIE = _IECreate("www.google.com") Local $jQuery = _jQuerify($oIE) MsgBox(0, "Version", "jQuery version: " & $jQuery.fn.jquery) MsgBox(0, "Example", "click ok to exit." & @CRLF & "Google logo will fade out by jQuery...") $jQuery('#hplogo').fadeOut(3000) ; jQuery will fade out the google logo EndFunc ;==>Example ; #FUNCTION# ==================================================================================================================== ; Name ..........: _jQuerify ; Description ...: ; Syntax ........: _jQuerify(Byref $oIE) ; Parameters ....: $oIE - Object variable of an InternetExplorer.Application. ; Return values .: an object variable pointing to the jQuery library ; Author ........: Chimp ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _jQuerify(ByRef $oIE) Local $jsEval, $jQuery, $otherlib = False ; create a reference to the javascript eval() function $oIE.document.parentWindow.setTimeout('document.head.eval = eval', 0) Do Sleep(250) $jsEval = Execute('$oIE.Document.head.eval') Until IsObj($jsEval) ; if jQuery is not already loaded then load it If $jsEval("typeof jQuery=='undefined'") Then ; check if the '$' (dollar) name is already in use by other library If $jsEval("typeof $=='function'") Then $otherlib = True Local $oScript = $oIE.document.createElement('script'); $oScript.type = 'text/javascript' ; If you want to load jQuery from a disk file use the following statement ; where i.e. jquery-1.9.1.js is the file containing the jQuery source ; (or also use a string variable containing the whole jQuery listing) ;~ $oScript.TextContent = FileRead(@ScriptDir & "\jquery-1.9.1.js") ; <--- from a file ; If you want to download jQuery from the web use this statement $oScript.src = 'https://code.jquery.com/jquery-latest.min.js' ; <--- from an url $oIE.document.getElementsByTagName('head').item(0).appendChild($oScript) Do Sleep(250) Until $jsEval("typeof jQuery == 'function'") EndIf Do Sleep(250) $jQuery = $jsEval("jQuery") Until IsObj($jQuery) If $otherlib Then $jsEval('jQuery.noConflict();') Return $jQuery EndFunc ;==>_jQuerify  
    • XaelloNegative
      By XaelloNegative
      Hi there.
      Im having some kind of a coder block here, 
      <td class="treeview ctl00_CenterContent_objTreeView_2" style="white-space:nowrap;"> <input type="checkbox" name="ctl00_CenterContent_objTreeViewn1CheckBox" id="ctl00_CenterContent_objTreeViewn1CheckBox"> <span class="ctl00_CenterContent_objTreeView_0 treeview ctl00_CenterContent_objTreeView_1" id="ctl00_CenterContent_objTreeViewt1" style="border-style:none;font-size:1em;"> <i class="fa fa-file-code-o fa-fw"> </i> <span data-placement="bottom" data-toggle="tooltip" title="" data-original-title="Tool tip for said part">REFUNDS</span></span></td> this is a code directly from the website im working with. I was thinking of inserting a javascript that would get the "REFUNDS" part. Any ideas on how to do so?
      Any thoughts will be highly appreciated.
    • Patryk
      By Patryk
      Dear Colleagues,
      I have no idea how to refer to style.display in my loop. There is a button like: 
      <input name="ctl00$bodyPlaceholder$btnFecharProcessamento" class="button" id="bodyPlaceholder_btnFecharProcessamento" style="display: none;" onclick="FecharJanelaProcessamento();return false;" type="submit" value="Fechar"> I want it to be clicked as soon as button's style change from style="display: none;" to  style= ="display: inline-block;" 
      This is what I got, but it's not working...
      Func GetButtons() $oButtons = _IEGetObjByName($oForm,"ctl00$bodyPlaceholder$btnFecharProcessamento",-1) $i = 0 While $i <> 1 For $oBtn In $oButtons If _IEFormElementGetValue($oBtn) = "Fechar" And $oBtn.document.style.display = "display: inline-block;" Then $i = 1 _IEAction($oBtn, "focus") _IEAction($oBtn, "click") ExitLoop EndIf Next WEnd EndFunc  
      I will really appreciate if you could help me with these loop!
    • Omnitica
      By Omnitica
      Hello!
      I'm new to the forums! Couldn't find any threads covering this issue. Sorry if I'm wrong.

      I'm having problems changing the text/value of a input box. The particular box doesn't have a name or id, just: class="jq_hotkeys_enabled form-control".
      This class appears multiple times throughout the source, so I don't think It's right to reference that object. 
      See image 1.
      However, I've managed to find a object with the name "ctl00$content$ctrl$ucServiceTime$rpServicetimes$ctl00$edtHiddenResourceHelper" which contains the value of the input box, and the id for the person in the dropdown/combobox left of it. (with "dummy-1" selected).
      See image 2.
      As you can see the value is 3982,4545     ( name , time )
      But when I try to change the value of it by doing:
      #include <IE.au3> Local $oIE = _IEAttach(WinGetHandle("[CLASS:IEFrame]"),"embedded") Local $oForm = _IEFormGetObjByName($oIE, "aspnetForm") Local $oInput = _IEFormElementGetObjByName($oForm, "ctl00$content$ctrl$ucServiceTime$rpServicetimes$ctl00$edtHiddenResourceHelper") _IEFormElementSetValue($oInput, "3982,1337") The box doesn't get its new value. I  can see in the source that it's changed though.
      See image 3.
       
      However, if I do: 
      #include <IE.au3> Local $oIE = _IEAttach(WinGetHandle("[CLASS:IEFrame]"),"embedded") Local $oForm = _IEFormGetObjByName($oIE, "aspnetForm") Local $oInput = _IEFormElementGetObjByName($oForm, "ctl00$content$ctrl$ucServiceTime$rpServicetimes$ctl00$edtHiddenResourceHelper") _IEFormElementSetValue($oInput, "3982,1337") $oIE.document.parentwindow.execScript("theForm.submit()") ; But it needs to reload the page The box gets its new value after the page reloads by the theForm.submit() function. 
      This is a bit unfortunate as I want the changes to happen instantly like when I type in the box with the keyboard... or select in the combobox.
      Maybe someone knows how I can do this? Looking forward to an answer! 
      Thanks in advance.
       
      Note: Unfortunately I can't provide with the real URL as it is constricted to employees in the company I work for, but let me know If I should provide anything else.
       



    • milos83
      By milos83
      How can I check if element is focused in Firefox using FF.au3 UDF?
      This is my try:
      I have prepared a function that checks if the object is focused:
       
      _FFCmd('FFau3.isfocused=function isfocused(a){try{return (a === document.activeElement)}catch(e){return}}') $oElm = _FFXPath("//*[@id='someId']") ConsoleWrite(_FFIsFocused($oElm)) Func _FFIsFocused($sElement = "") Local $isFoc = _FFCmd("FFau3.isfocused(" & $sElement & ")") Return $isFoc EndFunc ;==>_FFIsFocused Now, the javascript part is tested and it does return successfully.
      After a lot of try/fails I inserted an alert box in order to display the object being compared.
      Here is what I got
       
      The focused object is: [object XULElement]
      The object that I send for comparing is [object HTMLInputElement]
      Why is that?
       
       
×