Page 1 of 1

Multiplying with 2-d arrays

Posted: Tue Oct 30, 2012 11:45 am
by louisharrodine
Hi there,

This is my code: where n = the number of elements in the array "bigarray"



repeat with loop = 0 to n - 1
put bigarray[loop][0] into kmphour[loop][0]
if bigarray[loop][1] = 0 or bigarray[loop][2] = 0 then
put 0 into kmphour[loop][1] -- If either value = 0, the speed with also be 0
else
put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]
end if
end repeat



When I run it, it returns the error:

button "Start the program": execution error at line 132 (Operators *: error in left operand), char 49



Is it possible to multiply using arrays? Is there a fault with my code?

Thanks.

Re: Multiplying with 2-d arrays

Posted: Tue Oct 30, 2012 12:15 pm
by Thierry
Could you kindly tell us what is line 132 ?

This could help us to help you

Thierry

Re: Multiplying with 2-d arrays

Posted: Tue Oct 30, 2012 1:13 pm
by bn
Hi Louis,

I tried your code and it seems to work. Make a field and put this into a button:

Code: Select all

on mouseUp
   repeat with loop = 0 to 9 -- lets make 10 loops
      repeat with n = 0 to 2 -- with 3 subarrays per loop
         put random(3)-1 into bigarray[loop][n] -- fill the subarray with random numbers between 0 and 2
         put random(3)-1 into kmphour[loop][n]
      end repeat
   end repeat
   
  arrayDo bigArray, kmphour -- pass this to your routine
   
end mouseUp


on arrayDo bigarray, kmphour
   put the keys of bigarray into tKeys
   put the number of lines of tKeys into n
   repeat with loop = 0 to n - 1
      put bigarray[loop][0] into kmphour[loop][0]
      if bigarray[loop][1] = 0 or bigarray[loop][2] = 0 then
         put 0 into kmphour[loop][1] -- If either value = 0, the speed with also be 0
      else 
         put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]
      end if
   end repeat
   
   -- lets collect the data and display it in a field
   put 0 into loop
   repeat with loop = 0 to n -1
      put "Loop: " &  loop + 1  after tCollect
      put tab & tab & "km/h" && kmpHour[loop][1] & cr after tCollect
      
   end repeat
   delete last char of tCollect -- a return
   put tCollect into field 1
end arrayDo
If I understood you correctly your routine works. It must be another error.
Kind regards
Bernd

Re: Multiplying with 2-d arrays

Posted: Wed Oct 31, 2012 3:19 pm
by louisharrodine
Hi, thanks for your replies.

Line 132 is this part of the code:
put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]



And this is the entire program:

Code: Select all

   on mouseUp 
   
   #Define variables to be passed
   local filedirectory, n, bigarray, temp
   
   read_from_file filedirectory, n, bigarray, temp
   user_input n, bigarray
   Sort_and_display_highest_distances n, bigarray, temp
   display_fastest_speed temp, n, bigarray
   write_to_file filedirectory, bigarray, n
   
end mouseup 


on read_from_file @filedirectory, n, @bigarray, temp
   
   #Define local variables 
   local counter
   
   #Clear output field "text" 
   put empty into field "text" 
   
   #Empty variables - livecode saves values
   put empty into bigarray
   put empty into n
   put empty into filedirectory
   put empty into temp
   
   #Put file location into variable 
   put specialfolderpath("desktop") & "/box.txt" into filedirectory
   
   #If there is a file, read the records from the file
   if there is a file filedirectory then
      
      open file filedirectory 
      read from file filedirectory until EOF 
      close file filedirectory 
      
      #Put file into temporary variable 
      put it into temp 
      put the number of lines of temp into n #Get the number of lines from text file 
      split temp by comma 
      
      ###put temp[1] into line 2 of field "text"
      
      ##put 1 into counter
      
      #Nested loop which puts 1-D array "temp" into 2-D array "bigarray" 
      repeat with loop = 0 to n - 1 
         repeat with loop2 = 0 to 2 
            put temp[loop*3 + loop2 + 1] into bigarray[loop][loop2]##########Code works, but silly? Should just keep counter
            ####add 1 to counter 
         end repeat
      end repeat
      
   else # If there is not a file, create a new empty file
      open file filedirectory for write -- creates a file
      close file filedirectory -- closes/saves the file
   end if
   
end read_from_file 


on user_input @n, @bigarray
   
   #Define local variables
   local userinput 
   
   #Redefine "n" with bigarray as the subject - CLUNKY ENGLISH
   put the number of lines of (the keys of bigarray) into n 
   
   #Get new user input 
   ask "Where have you just been running?" 
   put it into userinput[0] 
   ask "In kilometres, how far did you run?" 
   put it into userinput[1] 
   ask "In minutes, how long did it take you to run those "&userinput[1]&" kilometres?" 
   put it into userinput[2] 
   
   #Put the user input at the bottom of the array 
   repeat with loop = 0 to 2 
      put userinput[loop] into bigarray[n][loop] 
   end repeat
   
   #The value of n must be increased by 1, as the number of records has been increased by 1
   add 1 to n
   
end user_input 


on Sort_and_display_highest_distances n, bigarray, temp
   
   #Clear temp value
   put empty into temp
   
   #Sort bigarray on distance high to low
   repeat with outer = n - 1 to 0 step -1 
      repeat with inner = 0 to outer - 1 
         if bigarray[inner + 1][1] > bigarray[inner][1] then 
            repeat with loop = 0 to 2 
               put bigarray[inner][loop] into temp[loop] 
               put bigarray[inner + 1][loop] into bigarray[inner][loop] 
               put temp[loop] into bigarray[inner + 1][loop] 
            end repeat
         end if
      end repeat
   end repeat
   
   put "These are the top 5 distances you have ever ran:" into line 1 of field "text" 
   
   repeat with loop = 0 to 4 # display the top 5 records 
      put "At "&bigarray[loop][0]&" you ran "&bigarray[loop][1]&" kilometres." into line loop + 3 of field "text" 
   end repeat
   
end Sort_and_display_highest_distances


on display_fastest_speed temp, n, bigarray
   
   #Clear temp variable value
   put empty into temp 
   
   #Define local variables
   local Kmphour, runlocation
   
   #Fill array "kmphour" with values of fields "distance"*"time taken", taken from array "bigarray"
   repeat with loop = 0 to n - 1
      put bigarray[loop][0] into kmphour[loop][0] #Put the location feild of "bigarray" into array "kmphour"
      if bigarray[loop][1] = 0 or bigarray[loop][2] = 0 then ###IS THIS NECESSARY? WHAT IF USER ENTERS 0?
         put 0 into kmphour[loop][1] -- If either value = 0, the speed with also be 0
      else 
               put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]
      end if
   end repeat
   
   #Sort kmphour high to low
   repeat with outer = n - 1 to 0 step -1 
      repeat with inner = 0 to outer - 1 
         if kmphour[inner + 1][1] > kmphour[inner][1] then 
            put kmphour[inner][1] into temp 
            put kmphour[inner + 1][1] into kmphour[inner][1]
            put temp into kmphour[inner + 1][1]
            put kmphour[inner][0] into runlocation
         end if
      end repeat
   end repeat
   
   #Display the fastest speed ran 
   put "The fastest speed at which you have ran is "&kmphour[0][1]&" kilometres per hour. This was at "&runlocation&"." into line 9 of field "text" 
   
end display_fastest_speed 


on write_to_file filedirectory, bigarray, n
   
   #Opens or creates a new file to be written to
   Open file filedirectory for write 
   
   #Write the user input to the file
   repeat with loop = 0 to n - 1 # Write all the records to the file
      if loop = 0 then 
         write bigarray[loop][0]&","&bigarray[loop][1]&","&bigarray[loop][2] to file filedirectory -- &LF 
      else if loop = n - 2 then 
         write ","&bigarray[loop][0]&","&bigarray[loop][1]&","&bigarray[loop][2]&LF to file filedirectory 
      else
         write ","&bigarray[loop][0]&","&bigarray[loop][1]&","&bigarray[loop][2] to file filedirectory -- &LF
      end if 
   end repeat 
   
   #Close file after it has been written to
   Close file filedirectory 
   
end write_to_file 


end mouseup


It all works fine until the sub-routine "display_fastest_speed", where upon it gives said error.



Any help would be great, as I have no idea how to proceed.

Louis

Re: Multiplying with 2-d arrays

Posted: Wed Oct 31, 2012 3:51 pm
by Mark
Hi Louis,

It looks like bigarray[loop][2] isn't a number. Maybe it is empty?

Mark

Re: Multiplying with 2-d arrays

Posted: Wed Oct 31, 2012 3:55 pm
by bn
Hi Louis,
I don't know whether you looked at the code I posted.
If you would do that you would see that the exact same line in your code

Code: Select all

put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]
does not throw an error in my feeding data to the handler.

I suggest you step through your code with the debugger and see if the variables are appropriately filled.

Furthermore a way do debug this is to isolate the problem and then if it is not solved by then post a the reproducible recipe for the error to occur. Also of help would be to know the structure of your data.

A sample stack with just the error and sample data would be best. Unfortunately you are not yet allowed to upload stacks. It takes some more posts to do that.

The most important step would be to go into the debugger and watch what is in the variables when the error occurs.

Kind regards
Bernd

Re: Multiplying with 2-d arrays

Posted: Wed Oct 31, 2012 5:58 pm
by sturgis
Do you mind providing a simple example of your data?

It looks like it is not a single line (based on your code), with items that are comma separated.

Is it like this?

3,2,4,5,6
2,3,4,7,8


or is it like this
4,3,4,5,6,
4,2,4,5,6, -- with trailing comma..

or is it only 2 items per line without trailing comma like this

1,3
3,12

If the 3rd or 1st is the way it is set up, when you use split by comma, you end up with an array like
array[1] = 1
array[2] = 3
3
array[3] = 12

I suspect your code can be greatly simplified (which also makes it easier to debug) but would need a simple example of the data to help optimize.


Also, again as far as the data goes, you might need to check for empty items. (1,3,,4) or confirm that there is no other data issue. Error in left operand is probably pointing at a non-numeric value at some location in your array that is being used for your calculation. So again, check for correct data in your array and eliminate that as a possibility.

Re: Multiplying with 2-d arrays

Posted: Wed Oct 31, 2012 7:13 pm
by louisharrodine
Hi there,

@Mark:

I thought that as well, so I put in the "if bigarray[loop][1] = 0 or bigarray[loop][2]" "put 0 into kmphour[loop][1]. So I'd thought that if bigarray[loop][2] was empty, it would go through the IF statement?


@Bernd

Thanks a lot for your reply. I had a full look over your code, and ran it in a separate program, and then in my own, and it did indeed work.

I went through the debug, but I could not see the values of either of the 2-d arrays "bigarray" and "kmphour". Upon hovering, they both showed:

1 =
2 =
3 =

However I am certain they do hold values: I put "Put bigarray[0][0] into line 4 of field "text" .... etc at various points and they do definitely hold and pass values.


@sturgis


This is an example of the data, and how it is imported.



The data is saved in a text file, and looks like this:

Haddington,4,20
,East Linton,20,100
,Home,10,50
,Gym,8,16



Then the data is read into the variable temp, which then stores it in 1 column:

temp[1] = Haddington
temp[2] = 4
temp[3] = 20
temp[4] = East Linton
temp[5] = 20
temp[6] = 100
etc....


Then with this loop:

Code: Select all

      #Nested loop which puts 1-D array "temp" into 2-D array "bigarray" 
      repeat with loop = 0 to n - 1 
         repeat with loop2 = 0 to 2 
            put temp[loop*3 + loop2 + 1] into bigarray[loop][loop2]
         end repeat
      end repeat

Which puts temp into bigarray like this:

bigarray[0][0] = Haddington
bigarray[0][1] = 4
bigarray[0][2] = 20
bigarray[1][0] = East Linton
bigarray[1][1] = 20
bigarray[1][2] = 100
ect...



I hope this makes it clear how the data is structured. At the end of the program i format it again to make it as it was at the start.

Re: Multiplying with 2-d arrays

Posted: Thu Nov 01, 2012 1:32 am
by sturgis
It is now clear yes, however looking things over I suspect there are easier ways. Going to post a little code here to clear up a few things.

Here is a simpler read_from_file. Bigarray and n are declared outside all handlers at the top of the script so that they are persistant script local variables.
No need to pass in values here because you set them all from inside the handler.

Code: Select all

on read_from_file 
   -- bigarray defined as script local at top, no declaration here. Makes it persistant. 
   -- handler locals are NOT persistant between calls. 
   #Define local variables 
   -- only need to declare if you have strict compilation mode on
   -- n is used several places and needs to be persistant, so using it as a script local at the top
   local counter, filedirectory, temp
   
   #Clear output field "text" 
   put empty into field "text" 
   
   #Empty variables - livecode saves values
   # since its declared as a script local, yes it needs to be cleared due to persistance 
   put empty into bigarray
   
   put specialfolderpath("desktop") & "/box.txt" into filedirectory
   
   #If there is a file, read the records from the file
   if there is a file filedirectory then
      
      
      -- could also do these three lines as a single command.. actually 4 lines. putting directly into temp
      ## put URL ("file:" & filedirectory) into temp 
      -- Depending on the file, might need to use "binfile:" instead of file, but from
      -- your example, dont' think so
      open file filedirectory 
      read from file filedirectory until EOF 
      close file filedirectory 
      put it into temp 
      
      put 0 into counter
      -- repeat for each is VERy fast. saves a split and a double loop. 
      -- loop through once and place stuff into big array
      repeat for each line tLine in temp
         put item 1 of tLine into bigArray[counter][0]
         put item 2 of tLine into bigArray[counter][1]
         put item 3 of tLine into bigArray[counter][2]
         add 1 to counter -- increment counter for next line
      end repeat
      
   else # If there is not a file, create a new empty file
      
      -- unchanged. Could do a single line "put empty into url ("file:" & filedirectory) instead. Either works fine.
      open file filedirectory for write -- creates a file
      close file filedirectory -- closes/saves the file
      
   end if
   
end read_from_file 

Userinput works well, though notice the comment where the 2 arrays are put together. An array can be placed into an array so you don't have to loop through elements and tack them on by hand.

Code: Select all

on user_input
   
   #Define local variables
   local userinput 
   
   #Redefine "n" with bigarray as the subject - CLUNKY ENGLISH
   -- since you start your array at 0 this works well without any extra hoops. Nice!
   put the number of lines of (the keys of bigarray) into n 
   
   #Get new user input 
   ask "Where have you just been running?" 
   put it into userinput[0] 
   ask "In kilometres, how far did you run?" 
   put it into userinput[1] 
   ask "In minutes, how long did it take you to run those "&userinput[1]&" kilometres?" 
   put it into userinput[2] 
   
   
   -- No need for repeat loop here, you can put an array into an array element directly. 
   #Put the user input at the bottom of the array 
   put userinput into bigarray[n]
   
   #The value of n must be increased by 1, as the number of records has been increased by 1
   
   add 1 to n
   
end user_input 


Having read through more of the code i'm struck by the thought that -- in this particular case-- arrays are not necessarily the best option. A flat file would work extremely well, and then when you need to do your sorts you can use the livecode abilities to get to the desired results pretty easy.

So for example, if you adjust your file format so that its a flat file with 3 items
location,distance,time
location,distance,time

its easy enough to add your new location distance time at the end of the file

If you have all your lines in a variable after loading from the file you can do
put the number of lines in myVariable into n
put theNewData into line (n + 1) of myVariable -- there are other ways do do this of course.

THen for your sorts.. distance is easy.

sort lines of myVariable descending numeric by item 2 of each -- will sort by item 2

For the speed use a temporary variable. Something along these lines. So if myVariable has the lines of data, items delimited by comma, rows by cr then

Code: Select all

put empty into temp
repeat for each line tLine in myVariable
put tLIne & comma & yourspeedcalculations go here & cr after temp
end repeat
delete the last char of temp
sort lines of temp descending numeric by item 4 of each
At this point temp contains your data sorted by speed (item 4 of each line) and all you have to do is grab the top line (or lines if you wish) (if there are that many) and use them as you see fit.

A complete rewrite of the script is here. Forgive me if you just really want to use arrays for this, and ignore the following code.

Code: Select all

   local bigVar,n,filedirectory -- all these are used in various handlers, declare once at top for persistance. 
on mouseUp 
   read_from_file
   user_input 
   Sort_and_display_highest_distances n, bigarray, temp
   display_fastest_speed
   write_to_file
   
end mouseup 


on read_from_file 
   local counter, temp
   
   #Clear output field "text" 
   put empty into field "text"    
   
   put specialfolderpath("desktop") & "/box.txt" into filedirectory
   
   #If there is a file, read the records from the file
   if (there is a file filedirectory) then
      put URL ("file:" & filedirectory) into bigVar 
   else
      -- no need to create a file here, it will be created by write_to_file
      put empty into bigVar
   end if
   
end read_from_file 


on user_input
   -- Could calculate speed as part of the user input in this handler
   -- it would end up being more efficient that way
   -- so that only a simple sort, no loops would be necessary
   -- to locate the fastest speed.  Speed could be stored in the file as an additional item.
   #Define local variables
   local userinput, distance
   
   put the number of lines of bigVar into n 
   
   #Get new user input 
   ask "Where have you just been running?" 
   put it & comma into userinput -- build up a string of items and tack it on to the end of bigVar which is the file contents
 
   ask "In kilometres, how far did you run?" 
   put it into distance
   put distance & comma after userinput 
     

 ask "In minutes, how long did it take you to run those "& distance &" kilometres?" 
   put it after userinput
   
   -- No need for repeat loop here, you can put an array into an array element directly. 
   #Put the user input at the bottom of the array 
   if bigVar is empty then
      put userinput into bigVar -- if its the first entry, no line break
   else
      put cr & userInput after bigVar -- else add line break
   end if
   #The value of n must be increased by 1, as the number of records has been increased by 1
   add 1 to n 
   
end user_input 


on Sort_and_display_highest_distances 
   #Clear temp value
   put empty into temp
   sort lines of bigVar descending numeric by item 2 of each -- sorts by distance
      
   if the number of lines in bigVar >= 5 then -- handle an empty or nearly empty file 
      put line 1 to 5 of bigVar into temp -- if more than 5 lines grab the first 5 after sort
   else
      put bigVar into temp -- otherwise grab em all
   end if
   -- loop for the number of lines in temp. Will be 1-5
      put "These are the top" & the number of lines in temp & " distances you have ever ran:" & cr into line 1 of field "text" 

   repeat for each line tLine in temp
            put "At "& item 1 of tLine &" you ran "& item 2 of tLine &" kilometres." & cr after field "text" 
   end repeat
end Sort_and_display_highest_distances


on display_fastest_speed temp, n, bigarray
   
   #Clear temp variable value
   put empty into temp 
   
   #Define local variables
   -- local Kmphour, runlocation -- not needed this way
   
   repeat for each line tLine in bigVar
      -- do calcs and build flat data in temp variable
      -- check to make sure i didn't munge your calculation
      put tLine & comma & item 2 of tLine /(item 3 of tLine / 60) & cr after temp
   end repeat
   -- after loop, item 4 of each line contains the speed
   delete the last char of temp -- remove extraneous line break
   
   sort lines of temp numeric descending by item 4 of each -- the first line should contain the fastest time now
   
   #Display the fastest speed ran 
   -- use the items in the first line of temp to display results
   put cr & "The fastest speed at which you have ran is "& item 4 line 1 of temp & " kilometres per hour. This was at "& item 1 line 1 of temp &"." & cr after field "text" 
   
end display_fastest_speed 


on write_to_file
   put bigVar into URL ("file:" & filedirectory)
end write_to_file 
EDIT:
Last comment on this.. If you are going to have large amounts of data you might consider shifting to a simple sqlite database for storage. It would work very well. To get your top 5 distances select from the database order by that field descending numeric, and set a limit to however many top entries you wish to pull out. You could store times in the database also to make selecting top times easy. (for that you can order by speed, limit 1, or I believe you can use the max() database function to locate the entry in question)


EDIT2: edited rewrite slightly to correct ask text.

Re: Multiplying with 2-d arrays

Posted: Thu Nov 01, 2012 2:11 am
by sturgis
Also just noticed this:
put bigarray[loop][1]/(bigarray[loop][2]*60) into kmphour[loop][1]
Should probably be this:

Code: Select all

put bigarray[loop][1]/(bigarray[loop][2] / 60) into kmphour[loop][1]
IE distance / (time in minutes / 60) rather than * 60. Otherwise you end up with km per second and you want to go the other direction.

Re: Multiplying with 2-d arrays

Posted: Fri Nov 02, 2012 12:19 pm
by louisharrodine
Hi,

Thanks alot for all of your help!

After trying both versions extensively, I've decided to stick mainly with arrays, but it's ended up as bit of a hydbrid anyway.

Thanks again for all your help,
Louis