PtokaX forum

Archive => Archived 4.0 boards => Help with Lua 4 scripts => Topic started by: Droid on 30 March, 2004, 21:54:16

Title: Help required with basic sort routine
Post by: Droid on 30 March, 2004, 21:54:16
Am relatively new to LUA and having a bit of a problem getting a sort routine to work.  Basically I have a table which is indexed by hub user name and contains scores for each of them.  The score and user info is written out to a file and then read in again when the bot first runs.  What I'd like to be able to do is sort the data at the time it is displayed.  I have tried doing it the long way by reading both the table indexes and values into 2 separate arrays and doing the sort that way but that gives an error message about comparing strings and numerical values.  Anyway, I'd much prefer to do the sort in the neatest and most efficient way and I'm assuming that would be by using the inbuilt sort function.  I came across some code in another script and wondered whether I could use something like this:

sort(TCopy,function(a,b) return(a[2].Score>b[2].Score) end)

but I couldn't get it to work and didn't fully understand it.

Just for clarity the data I have in the table is assigned as follows:

Array[curUser.sName] = value 1 etc etc

Can anyone help?
Title:
Post by: plop on 30 March, 2004, 23:12:26
what you have is an associative table, and those can not be sorted.
but there are tricks 2 work around this.
stuff all the vallues into a array and sort that.
now use that array 2 make the table show in the correct order.
won't help much 2 fully sort the table as lua keeps moving the things around in them.

plop
Title:
Post by: chill on 30 March, 2004, 23:29:44
hmm...
Title:
Post by: Droid on 30 March, 2004, 23:58:42
QuoteOriginally posted by plop
what you have is an associative table, and those can not be sorted.
but there are tricks 2 work around this.
stuff all the vallues into a array and sort that.
now use that array 2 make the table show in the correct order.
won't help much 2 fully sort the table as lua keeps moving the things around in them.

plop

OK, well as I said I did try it that way but I'm obviously still doing something wrong as when I try and copy the data into 2 arrays and then sort and display it what happens is that the data is still not sorted.  Also, if any of the users scores change and I then subsequently try and sort and display the scores I get a syntax error "attempt to compare string with number".  I'm sure its something simple but as I'm very new to LUA I'm just not seeing it.  The code is:


      i = 0
      for index, value in pointArray do
      Users[i+1] = index
      Scores[i+1] = value
      i = i + 1
   end

   for passNum=1,i-1,1 do
      for i=1,i-passNum,1 do
         if Scores > Scores[i+1] then
            temp = Users
            Users=Users[i+1]
            Users[i+1]=temp
            temp = Scores
            Scores = Scores[i+1]
            Scores[i+1] = temp
         end
      end
   end
Title:
Post by: Droid on 31 March, 2004, 00:02:28
I just read up a bit more....  should I be using rawget and rawset to read and write the values in the arrays?
Title:
Post by: chill on 31 March, 2004, 00:11:32
you are into c or cpp ?, luckily in lua there are no arrays and no string arrays.

so the most easiest and best way to understand is this one. I think imao.

local TCopy = { n = 0} -- is a TCopy table

foreach(pointArray, function(i,v) tinsert(%TCopy, { i,v }) end) -- Copy the data from one to the other.

sort(TCopy, function(a,b) return ( a[2] > b[2]) end) -- sort the table

and so on then list is up.
Title:
Post by: Droid on 31 March, 2004, 00:33:16
QuoteOriginally posted by chill
you are into c or cpp ?, luckily in lua there are no arrays and no string arrays.

so the most easiest and best way to understand is this one. I think imao.

local TCopy = { n = 0} -- is a TCopy table

foreach(pointArray, function(i,v) tinsert(%TCopy, { i,v }) end) -- Copy the data from one to the other.

sort(TCopy, function(a,b) return ( a[2] > b[2]) end) -- sort the table

and so on then list is up.

Hi Chill,

Thanks for your message.  I've only been looking at Lua for literally a couple of days so I don't really know these kind of routines yet.  But I'm confused now.  If I have what plop says is an associative table which can't be sorted directly what difference does it make if I make an exact copy of it in TCopy?  Surely I still have the same problem?   Anyway, I put the code you listed into my script but when I run it I now get an error message from the display routine:

attempt to concat local `value' (a table value)

The display routine used to be:

i=1
for index, value in pointArray do
curUser:SendData(i..". "..index..",   points: "..value)
i=i+1
end

I replaced the pointArray with TCopy as:

i=1
for index, value in TCopy do
curUser:SendData(i..". "..index..",   points: "..value)
i=i+1
end

and that's when I get the syntax error.
Title:
Post by: chill on 31 March, 2004, 00:43:01
best would be if you post the whole script.
but else you create not a real copy of the table you create associative copy ( one that can be sorted ).

just read you code sure in TCopy you have value as a table so to read out TCopy do this

foreachi(TCopy, function(_,v) curUser:SendData("nick: "..v[1]..", ponits: "..v[2]) end)

or in you case

for index,value in TCopy do if index ~= "n" then curUser:SendData(index.."  "..value[1].."  "..value[2])  end end
Title:
Post by: Droid on 31 March, 2004, 01:29:35
QuoteOriginally posted by chill
best would be if you post the whole script.
but else you create not a real copy of the table you create associative copy ( one that can be sorted ).

just read you code sure in TCopy you have value as a table so to read out TCopy do this

foreachi(TCopy, function(_,v) curUser:SendData("nick: "..v[1]..", ponits: "..v[2]) end)

or in you case

for index,value in TCopy do if index ~= "n" then curUser:SendData(index.."  "..value[1].."  "..value[2])  end end


Hi Chill,

Thanks for your patience in trying to help me with this problem.  I've gotten a little further but the sort still isn't working.  This is what happens now:



I put debug in to display the original contents of pointArray and I get this:


1. Paul,   points: 35
2. Tom,   points: 38
3. Fred,   points: 291
4. Chas,   points: 27



Then this code is run:

local TCopy = { n = 0} -- is a TCopy table

foreach(pointArray, function(i,v) tinsert(%TCopy, { i,v }) end) -- Copy the data from one to the other.



Now I display the contents of TCopy using the following code:

for index,value in TCopy do
 if index ~= "n" then curUser:SendData(index.." "..value[1].." "..value[2])
 end
 end


and I get:

1 Paul 35
2 Tom 38
3 Fred 291
4 Chas 27

OK, so both indexes and values have been copied successfully from pointArray into TCopy. So far so good.  The I run the sort with this code:

sort(TCopy, function(a,b) return ( a[2] > b[2]) end) -- sort the table


I display the data again using the code:

for index,value in TCopy do
 if index ~= "n" then curUser:SendData(index.." "..value[1].." "..value[2])
 end
 end
 
and I get:
 
1 Tom 38
2 Paul 35
3 Fred 291
4 Chas 27



So, the sort routine doesn't seem to have worked?

I could paste the whole script but everything works fine except this one function.
Title:
Post by: plop on 31 March, 2004, 02:06:56
i think this example can help you understand whats going on in that sort function you found.
you need the lua command line 2 execute this script.
-- the associative table
table = { ["Paul"]=35, ["some1"]= 27, ["Tom"]=38, ["Fred"]= 291, ["Chas"]= 27}

-- lets show the table like it is.
print("the unsorted table")
for a,b in table do
   print(a.." has "..b.." points")
end

print("")
print("now lets sort it")

-- build the temp array we need 2 sort the table
array = {}
-- lets make the temp table (we need this just incase ppl have the same amount of points)
Ttable = table

-- stuff all scores (vallue's) into the array.
for a,b in table do
   tinsert(array, b)
end

-- sort the array
sort(array)

-- now lets go thru the array and retrieve all who have that amount of points.
for i=1,getn(array) do -- start the loop thru the array
   for a,b in Ttable do  -- start the loop thru the temp table
      if b == array[i] then -- see if the scores match
         print(a.." has "..b.." points") -- if yes then print them
         Ttable[a]=nil -- remove the printed 1 from the temp table 2 remove doubles
         break -- breaking the iner loop 2 continue the outer loop
      end
   end
end
Title:
Post by: chill on 31 March, 2004, 10:15:07
droid, hmm.. dunno  well at least it shows that inassociative tables, do not have their indexes moved around like associative ones :).

To help you understand the sort func read this, its like this if your table ( no arrays in LUA :) ), looks like

table = {
[1] = 3,
[2] = 6,
[3] = 1,
["n"] = 3,
}

then you can sort it like

sort(table)


but the table TCopy looks like this

TCopy = {
[1] = { [1] = "nick1", [2]  = 6 },
[2] = { [1] = "nick2", [2] = 3 },
["n"] = 2,
}

so you need to tell LUA what to sort

sort(TCopy, function(a,b) return (a[2] > b[2]) end) -- sorts for points.

sort(TCopy, function(a,b) return (a[1] < b[1]) end) -- sorts the nicks.

you see we tell LUA what to sort, where a and b represent the value of the indexes, in this case a table again.

to do a fast readout of a inassociative table you do

foreachi(TCopy, function(i,v)
rank = i
nick = TCopy[i][1] or v[1]
points = TCopy[i][2] or v[2]
end)

foreachi is syntactic sugar for for

for i = 1,getn(TCopy) do
-- only you do not have the value called to do so do
v = TCopy[i]
end

btw all this get more clear when reading the lua manual.

I do admit, that TCopy is bigger than, only the table Copy of the points, but at least then you can access both nick and ponits in one table, and you need not to hash for the other value (nick).
Title:
Post by: Droid on 31 March, 2004, 17:58:51
To chill and plop:

Thanks for all your help guys.  I really learned a bunch of stuff from your answers.  And the reason that I was still getting errors with the sort was because when I first wrote the original script I had saved the actual score data out as strings rather than numbers.  Later on when I had modified the script and was trying to get the sort to work I had forgotten about this.  Once I edited the scores file and removed the quotes round the scores everything worked sweet.