Jump to content
Sign in to follow this  
txn

Subordinated searh in a 2D array

Recommended Posts

txn

Let's say you've got a 2D array like this:

Local $avArray[5][3] = [ _
   ["link1", "title1", "text0"], _
   ["link2", "title2", "text0"], _
   ["link3", "title3", "text0"], _
   ["link4", "title3", "text1"], _
   ["link5", "title2", "text1"]]

And you want to find the index number of the array containing "title3" and "text0". You would write something like this:

For $i = 0 To UBound($avArray) - 1
   $match = $avArray[$i]
   If StringInStr($match[1], "title3") And StringInStr($match[2], "text0") Then
      Return $match[0]
   EndIf
Next

Right? Now let's say that, if in $avArray there's no "text0" string, you would settle for matching only "title3". How would you do that? Do you go through $avArray again with another For/Next loop? And if you would settle also for another option (say "title2") so that just putting an Else inside the first loop wouldn't do the trick?

Thanks.

Edited by txn

Share this post


Link to post
Share on other sites
Melba23

txn,

This seems to work for me: ;)

#include <Constants.au3>

Local $avArray[5][3] = [ _
   ["link1", "title1", "text0"], _
   ["link2", "title2", "text0"], _
   ["link3", "title3", "text0"], _
   ["link4", "title3", "text1"], _
   ["link5", "title2", "text1"]]

$sMatch = _Search($avArray, "title3", "text0", "??", "title2")
MsgBox($MB_SYSTEMMODAL, "Found", $sMatch)

; Mode:  "?." = match title only; ".?" = match text only; "??" = match both
Func _Search($aArray, $sTitle, $sText, $sMode, $sAlt_Title = "", $sAlt_Text = "")

    Local $fFound_Title, $fFound_Text, $fFound_Alt_Title, $fFound_Alt_Text

    For $i = 0 To UBound($aArray) - 1
        ; Clear all flags
        $fFound_Title = False
        $fFound_Text = False
        $fFound_Alt_Title = False
        $fFound_Alt_Text = False
        ; Look for titles
        If StringInStr($aArray[$i][1], $sTitle) Then $fFound_Title = True
        If $sAlt_Title Then
            If StringInStr($aArray[$i][1], $sAlt_Title) Then $fFound_Alt_Title = True
        EndIf
        ; Look for texts
        If StringInStr($aArray[$i][2], $sText) Then $fFound_Text = True
        If $sAlt_Text Then
            If StringInStr($aArray[$i][2], $sAlt_Text) Then $fFound_Alt_Text = True
        EndIf

        MsgBox($MB_SYSTEMMODAL, "Element: " & $i, $fFound_Title & @CRLF & $fFound_Text & @CRLF & $fFound_Alt_Title & @CRLF & $fFound_Alt_Text)

        ; Now check mode to see if we have a match
        Switch $sMode
            Case "?." ; Only looking for title
                If $fFound_Title Then
                    Return $aArray[$i][0]
                ElseIf $sAlt_Title Then
                    If $fFound_Alt_Title Then
                        Return $aArray[$i][0]
                    EndIf
                EndIf
            Case ".?" ; Only looking for text
                If $fFound_Text Then
                    Return $aArray[$i][0]
                ElseIf $sAlt_Text Then
                    If $fFound_Alt_Text Then
                        Return $aArray[$i][0]
                    EndIf
                EndIf
            Case "??" ; Looking for both
                If $fFound_Title And $fFound_Text Then
                    Return $aArray[$i][0]
                Else
                    ; Accept an alt title?
                    If $sAlt_Title Then
                        If $fFound_Alt_Title And $fFound_Text Then
                            Return $aArray[$i][0]
                        EndIf
                    EndIf
                    ; Accept an alt text?
                    If $sAlt_Text Then
                        If $fFound_Title And $fFound_Alt_Text Then
                            Return $aArray[$i][0]
                        EndIf
                    EndIf
                    ; Accept both alts?
                    If $sAlt_Title And $sAlt_Text Then
                        If $fFound_Alt_Title And $fFound_Alt_Text Then
                            Return $aArray[$i][0]
                        EndIf
                    EndIf
                EndIf
        EndSwitch
    Next

EndFunc
I hope the parameters and logic flow are understandable, but please ask if not. :)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
txn

Thanks for your reply Melba23.

Actually I figured out I'm not dealing with a 2d array but rather with an array of arrays (returned by StringRegExp with flag 4). Does it make difference?

As for your code, the parameters and logic flow are absolutely understandable, and your solution is certainly more elegant and portable than going like:

For $i = 0 To UBound($avArray) - 1
   $match = $avArray[$i]
   If StringInStr($match[1], "title3") And StringInStr($match[2], "text0") Then
      Return $match[0]
   EndIf
Next
For $i = 0 To UBound($avArray) - 1
   $match = $avArray[$i]
   If StringInStr($match[1], "title3") Then
      Return $match[0]
   EndIf
Next
For $i = 0 To UBound($avArray) - 1
   $match = $avArray[$i]
   If StringInStr($match[1], "title2") Then
      Return $match[0]
   EndIf
Next

But I see there's a lot of nested statements in your code. Is it preferable than looping through the array over and over?

 

Edit: so my nested arrays should actually be declared like below. Sorry for misleading you, I thought that 2d arrays and nested arrays were the same thing (and to be honest I still don't really get the difference :ermm: )

Global $one[3] = ["link1", "title1", "text0"]
Global $two[3] = ["link2", "title2", "text0"]
Global $three[3] = ["link3", "title4", "text0"]
Global $four[3] = ["link4", "title4", "text1"]
Global $five[3] = ["link5", "title6", "text1"]
Global $avArray[5] = [$one, $two, $three, $four, $five]
Edited by txn

Share this post


Link to post
Share on other sites
kylomas

txn,

There is a tutorial on arrays here.

Briefly, you can visualize 1D arrays as a list and 2D arrays as a spreadsheet.  In your example you have a 1D array where each element (row) is an array.  This is distinctly different from a 2D array and rarely used (some of the heavy hitters may disagree).

Maybe the following example will help...

; $avArray is a 1D array where each cell points to a 1D array.
; This is completely different from a 2D array both in concept and use.

Global $one[3] = ["link1", "title1", "text0"]
Global $two[3] = ["link2", "title2", "text0"]
Global $three[3] = ["link3", "title4", "text0"]
Global $four[3] = ["link4", "title4", "text1"]
Global $five[3] = ["link5", "title6", "text1"]
Global $avArray1[5] = [$one, $two, $three, $four, $five]

; The above could be expressed as a 2D array as follows:

Global $avArray2[5][3] = [ _
                         ["link1", "title1", "text0"], _
                         ["link2", "title2", "text0"], _
                         ["link3", "title4", "text0"], _
                         ["link4", "title4", "text1"], _
                         ["link5", "title6", "text1"] _
                         ]

; Each "row" of $avArray1 can be accessed as follows.  Each element needs to be copied to an interim array
; (there may some other way to do this that I am not aware of)

ConsoleWrite(@lf & '!Printing $avArray1[$one]' & @LF)
local $aTmp = $avArray1[$one]
for $1 = 0 to ubound($aTmp) - 1
    ConsoleWrite($aTmp[$1] & @LF)
Next

; The above would need to be repeated for each "row" of $avArray1 whereas a 2D array is much easier to access:

ConsoleWrite(@lf & '!Printing $avArray2' & @LF)
for $1 = 0 to ubound($avArray2) - 1
    for $2 = 0 to ubound($avArray2,2) - 1           ; note the use of the dimension indicator
        ConsoleWrite($avArray2[$1][$2] & ' ')
    Next
    ConsoleWrite(@LF)
Next
ConsoleWrite(@LF)

kylomas

edit:

But I see there's a lot of nested statements in your code. Is it preferable than looping through the array over and over?

 

In the _Search function the top for..next loop is used to iterate through the array testing for equality and setting switches.  The case statement (switch...endswitch) is then used to decide what to return to the caller.  That way the array is only pased once.

Edited by kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

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
Sign in to follow this  

×