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?
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
hmm...
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
I just read up a bit more.... should I be using rawget and rawset to read and write the values in the arrays?
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.
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.
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
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.
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
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).
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.