max() function over arrays, single and multidimensional

Anything beyond the basics in using the LiveCode language. Share your handlers, functions and magic here.

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
SparkOut
Posts: 2949
Joined: Sun Sep 23, 2007 4:58 pm

max() function over arrays, single and multidimensional

Post by SparkOut » Sun Aug 23, 2009 7:26 pm

Working with arrays, I've become aware of a need to find a max value and return the key corresponding to that value.

Firstly, is there a way (well, apart from what I've already done, getting the max value from the array and then looping through the keys to see if the corresponding value matches the found max) to return the key of the max array value?

Secondly, what's the best approach to finding the max value in the second tier (or potentially further, to make this a generic case) of a multidimensional array?

Such as:

theArray[1]["name"] ="John"
theArray[1]["age"] = 15
theArray[2]["name"] ="Paul"
theArray[2]["age"] = 21
theArray[3]["name"] ="George"
theArray[3]["age"] = 19
theArray[4]["name"] ="Ringo"
theArray[4]["age"] = 18

How would you recommend I get the key 2 from the max age? Any suggestions gratefully received.

Mark Smith
Posts: 179
Joined: Sat Apr 08, 2006 11:08 pm
Contact:

Post by Mark Smith » Sun Aug 23, 2009 9:57 pm

Here's a recursive function that should work (I haven't tested it)

Code: Select all

function arrayMax pArray, pMax
  repeat for each key k in pArray
    if pArray[k] is an array then
      put arrayMax(pArray[k], pMax) into pMax
    else
      if pArray[k] is a number then put max(pArray[k], pMax) into pMax
    end if
  end repeat
  return pMax
end arrayMax
Best,

Mark

Mark Smith
Posts: 179
Joined: Sat Apr 08, 2006 11:08 pm
Contact:

Post by Mark Smith » Sun Aug 23, 2009 10:01 pm

Scratch that! I just re-read the question - you want the key of the max value...hmmm...

SparkOut
Posts: 2949
Joined: Sun Sep 23, 2007 4:58 pm

Post by SparkOut » Sun Aug 23, 2009 10:15 pm

Thanks Mark.
It's nifty using recursion but this walks the whole array/subarrays and gets the max from any key in the subarray. (It also barfs because of having a SQL datetimestamp in there, but I could trap for that.)

What I'm really looking for the (top level) key to be returned for the key for which a known subkey can be tested for the max value. As in the pseudo data above, I'd like a function that looks at the ["age"] subkey and finds the max of 21, thereby returning 2 as the top level key. I can then get the name for key 2 being returned as "Paul" (as well as the other associated data in other keys).

So far I have made functions that walk down two dimensions as:

Code: Select all

function fnGetKeyFromArrayValue pArray, pValue, pMultiKey
-- pass the array to walk, the value to search for (in this case the max of the "age" key that was returned from the other function beforehand, and the key name that is to be searched.
   local tKey
   if pArray is not an array then
      return "Error: not an array"
   else if pValue is empty then
      return "Error: no search value supplied"
   else if pMultiKey is not empty then
      put fnGetSubArray(pArray, pMultiKey) into pArray
   end if
   if pArray begins with "Error" then
      return pArray
   else
      repeat for each line tKey in the keys of pArray
         if pArray[tKey] is pValue then
            return tKey
         end if
      end repeat
   end if
   return "No matching value found"
end fnGetKeyFromArrayValue

function fnGetSubArray pArray, pMultiKey
   local tKey, tArray
   if pArray is not an array then
      put "Error: not an array" into tArray
   else if pMultiKey is empty then
      put "Error: no subkey value supplied" into tArray
   else
      repeat for each line tKey in the keys of pArray
         put pArray[tKey][pMultiKey] into tArray[tKey]
      end repeat
   end if
   return tArray
end fnGetSubArray
This works if I call the routines correctly with the right parameters, by calling

Code: Select all

put max(fnGetSubArray(theArrayA,"age")) into theMaxAge
put fnGetKeyFromArrayValue(theArrayA, theMaxAge, "age") into theMaxKey
to return the max value first and then get the key, but I was hoping for something more elegant. I'm surprised I'm having such a difficulty with it - with RunRev the problem is usually just picking which of the many ways to handle it.


Edit:
Mark Smith wrote:Scratch that! I just re-read the question - you want the key of the max value...hmmm...
Yes, thanks, sorry cross posted.

Mark Smith
Posts: 179
Joined: Sat Apr 08, 2006 11:08 pm
Contact:

Post by Mark Smith » Sun Aug 23, 2009 10:25 pm

Well, I've come up with this, which may help or not:

Code: Select all

on mouseUp
   put "paul" into tArray[1]["name"]
   put 21 into tArray[1]["age"]
   put "george" into tArray[2]["name"]
   put 19 into tArray[2]["age"]
   put "john" into tArray[3]["name"]
   put 20 into tArray[3]["age"]
   put "ringo" into tArray[4]["name"]
   put 18 into tArray[4]["age"]
   
   put flattenArray(tArray) into tList
   sort lines of tList numeric descending by item -1 of each
   put tList
end mouseUp

function flattenArray pArray
   repeat for each key k in pArray
      if pArray[k] is an array then
         put flattenArray(pArray[k]) into tTempList
         repeat for each line L in tTempList
            put k & comma & L & cr after tList
         end repeat
      else
         put k & comma & pArray[k] & cr after tList
      end if
   end repeat
   return tList
end flattenArray
so the flattenArray function returns a list like:

1,name,paul
1,age,21
2,name,george
etc...

Which looks like it might be usable in this case.

Cheers,

Mark

SparkOut
Posts: 2949
Joined: Sun Sep 23, 2007 4:58 pm

Post by SparkOut » Sun Aug 23, 2009 11:01 pm

Very nice, thanks very much Mark. Adding a needle match on the key means I can return a simple filtered list of the values for the key concerned, making it easy to sort and get the max, as in:

Code: Select all

function flattenArray pArray, pNeedleKey
   repeat for each key k in pArray 
      if pArray[k] is an array then 
         put flattenArray(pArray[k],pNeedleKey) into tTempList 
         repeat for each line L in tTempList 
            put k & comma & L & cr after tList 
         end repeat 
      else
         if k is pNeedleKey then
            put k & comma & pArray[k] & cr after tList 
         end if
      end if 
   end repeat 
   return tList 
end flattenArray

So I can put flattenArray(tArray,"age")

on mouseUp 
   put "paul" into tArray[1]["name"] 
   put 21 into tArray[1]["age"] 
   put "george" into tArray[2]["name"] 
   put 19 into tArray[2]["age"] 
   put "john" into tArray[3]["name"] 
   put 20 into tArray[3]["age"] 
   put "ringo" into tArray[4]["name"] 
   put 18 into tArray[4]["age"] 
    

   put flattenArray(tArray,"age") into tList 
   sort lines of tList numeric descending by item -1 of each 
   put item 1 of line 1 of tList into theKeyNeeded
   put theKeyNeeded -- returns 1, as tArray[1]["age"] holds 21 which is the max.
end mouseUp 
That's much appreciated, thanks again Mark.

Mark Smith
Posts: 179
Joined: Sat Apr 08, 2006 11:08 pm
Contact:

Post by Mark Smith » Sun Aug 23, 2009 11:08 pm

Cool, these little coding challenges are always interesting!

Best,

Mark

SparkOut
Posts: 2949
Joined: Sun Sep 23, 2007 4:58 pm

Post by SparkOut » Sun Aug 23, 2009 11:14 pm

Yes - I'm still a bit surprised that it was "a little challenge" though - I've got so used to finding a neat way of getting something out of Rev's built in stuff that I was convinced it was just me being stupid and missing a function that was just waiting for me to use. Walking the array seems a bit unnatural (albeit obvious that I should, in hindsight).

Post Reply