Search Values of Array in "One Go"

Sannyasin Brahmanathaswami brahma at hindu.org
Fri Aug 25 11:43:10 EDT 2017


@ Mark Waddingham

Awesome! thanks, I will test this later… 

Yes, my solution, at the urging of our Cohorts of the Round Table LiveCode Data Diggers, 
who earlier said "Don't go looking for your needles in arrays." (

I just reformulated the SQL quaryand passed it back "up" to the stack script which fetched the original complete data set.
That worked, but there are many use cases where this will be a better solution.

in the context of songs  I guess we iterate several times through this example to a case where


[title %like% "laughter" OR subtitle %like% "laughter" OR description %like% "laughter" 

AND

genre = "Songs By Nerds"

AND

theme = "Never Say Can't"


requires three trips to the mall:

array contains "Laughter"  
  AND
array contains " Songs By Nerds "  
  AND
array contains "Never Say Can't"  

But these are very small data sets, relatively speaking.. so it will be fast.  But what serialization results is unclear… 




 

On 8/24/17, 11:03 PM, "use-livecode on behalf of Mark Waddingham via use-livecode" <use-livecode-bounces at lists.runrev.com on behalf of use-livecode at lists.runrev.com> wrote:

    I think you may have already found a solution to what you want to do... 
    However, you'll find my version below.
    
    The arrayFindElementsContainingString command is a generic handler which 
    will search all elements of an array recursively for containing pNeedle.
    
    It returns a sequence (numerically indexed array) of array paths 
    containing the needle.
    
    The handler exploits the 'dynamic path' lookup feature of arrays. If you 
    construct a sequence (numerically keyed array starting at 1) array of 
    strings, you can use that sequence in [ ... ], and the engine will treat 
    it as a sequence of keys. e.g.
    
       put "foo" into tPath[1]
       put "baz" into tPath[2]
       put tArrayA[tPath] into field "Result"
    
    Here the last line is equivalent to tArrayA["foo"]["baz"].
    
    (Note this all works on arrays and strings, the test handler uses Json 
    as a convenient way to represent an array in a field!)
    
    -------- TEST HANDLER
    -- Requires a field "Results"
    -- Requires a field "Json" containing the JSON form of the array to be 
    searched
    -- Requires a field "Needle" containing the string to search for
    -- Requires a field "Results"
    
    /* Test the array finding */
    command testArrayFind pNeedle
        /* Clear the results field */
        put empty into field "Results"
    
        /* Get an array which is JSON encoded in field "Json" as an array */
        local tArray
        put JSONImport(field "Json") into tArray
    
        /* Search the array for the needle, fetched from field "Needle" */
        arrayFindElementsContainingString tArray, field "Needle"
    
        /* Iterate over each found path */
        repeat for each element tFoundPath in it
           /* Each path is a numerically keyed array (sequence), these can be 
    used
           * directly as array indicies, the engine will iterate through the 
    elements of
           * the sequence to get the keys to use */
           local tValue
           put tArray[tFoundPath] into tValue
    
           /* Create a slash delimited list of keys (note - this won't work 
    if any of the
           * keys in the path contain '/'!). */
           combine tFoundPath with "/"
    
           /* Show the list of results in field "Results" in the form:
           * slash delimited path : value
           */
           put tFoundPath & ":" & tValue & return after field "Results"
        end repeat
    end testArrayFind
    
    -------- LIBRARY FUNCTIONALITY
    
    /* Search all elements of pArray for containment of pNeedle. The
      * command returns a numerically keyed array in 'it', each element of
      * which is an array path to an element containing pNeedle. */
    command arrayFindElementsContainingString pArray, pNeedle
        /* We expect an array for pArray */
        if pArray is not an array and pArray is not empty then
           throw "pArray must be an array"
        end if
    
        /* We expect a string for pNeedle */
        if pNeedle is an array then
           throw "pNeedle must be a string"
        end if
    
        /* As arrays are recursive, we pass through the current base path
         * for the sub-array being searched to an auxillary private command 
    */
        local tBasePath
        put empty into tBasePath
    
        /* The auxillary private command accumulates complete paths in
         * tPaths, which is a numerically keyed array (sequence). */
        local tPaths
        put empty into tPaths
        _arrayFindElementsContainingString pArray, pNeedle, tBasePath, tPaths
    
        /* Using 'return for value' returns the value in 'it' in the caller. 
    */
        return tPaths for value
    end arrayFindElementsContainingString
    
    private command _arrayFindElementsContainingString pArray, pNeedle, 
    pBasePath, @xFoundPaths
        repeat for each key tKey in pArray
           /* Fetch the value of the key */
           local tElement
           put pArray[tKey] into tElement
    
           /* Create a new path from the base path by appending the current 
    key */
           local tPath
           put pBasePath into tPath
           put tKey into tPath[the number of elements in tPath + 1]
    
           /* What we do depends on the content of the element */
           if tElement is an array then
              /* If the element is an array, then we recurse passing through 
    the path to this key
               * as the base path */
              _arrayFindElementsContainingString tElement, pNeedle, tPath, 
    xFoundPaths
           else if tElement contains pNeedle then
              /* If the element is not an array, it must be a string-like 
    thing so we can check for
               * for containment of pNeedle, and if it does contain the 
    needle we append the
               * path to the key to the xPaths sequence */
              put tPath into xFoundPaths[the number of elements in 
    xFoundPaths + 1]
           end if
        end repeat
    end _arrayFindElementsContainingString



More information about the use-livecode mailing list