|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sat May 09, 2009 6:27 am
Numeric sorting and output with gag |
Hello. I'm am trying to make something that will sort a variable in numerical order. I have used the code from here :http://forums.zuggsoft.com/forums/viewtopic.php?p=134087&highlight=.
Now I would like to modify this code so that it :
a) lists the numbers from highest to lowest, instead of lowest to highest as it is now,
b) outputs on one line instead of separate lines, so that I can 'say' it on the MUD, and
c) make it so that it doesn't show any entries with 0 as a value.
If anyone would be kind enough to point me in the right direction I would be most appreciative. Thanks!
This is the function that I'm using:
Code: |
f zs.numparam < 1 then return "" end
local tbl = zs.param(1)
if type(tbl) ~= "table" then return tbl end
local errstr = "All Items in list given to NSort must be a number"
table.sort(tbl,function(a,b) return assert(tonumber(a),errstr)< assert(tonumber(b),errstr) end)
table.sort(tbl)
return table.concat(tbl,"|") |
And the alias for the output:
Code: |
LOCAL $temp
#LOOPDB @order_list {#ADDKEY $temp %val %key}
#FORALL @NSort(%dbkeys($temp)) {#WIN communication %i = %db($temp,%i)} |
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat May 09, 2009 12:03 pm |
This post is utter poppycock, best to skip it. I'll leave the contents here for historical purposes :P
There's definitely something funky going on here, and it's a good demonstration of why it's important to use informative errors :P
I played around with this for a bit and ended up here:
Code: |
<class name="lua_test" id="1">
<func name="NSort" language="Lua" id="2">
<value>if zs.numparam < 1 then return "too many params" end
local tbl = zs.param(1)
if type(tbl) ~= "table" then return "argument not a table, given " .. type(tbl) end
local errstr = "All Items in list given to NSort must be a number"
table.sort(tbl,function(a,b) return assert(tonumber(a),errstr)< assert(tonumber(b),errstr) end)
table.sort(tbl)
return table.concat(tbl,"|")</value>
</func>
<alias name="test" id="3">
<value>temp=""
#LOOPDB @order_list {#ADDKEY @temp %val %key}
#lua {print("temp is " .. type(zs.var.temp))}
keys = %dbkeys(@temp)
#lua {print("keys is " .. type(zs.var.keys))}
$result = @NSort(%dbkeys(@temp))
#show $result
//#forall $result {#say %i = %db(@temp,%i)}</value>
</alias>
<var name="order_list" type="Record" id="4">lol=4543|hax=124124151|bob=2352352</var>
<var name="temp" type="Literal" id="5"/>
<var name="keys" type="StringList" id="6"/>
</class> |
which, if you type test, will show you where the problem lies - although %dbkeys returns a table, once it's passed to the function it somehow turns back into a string. Also, $temp (@temp in this example) somehow contains a string as well, which is weird.
I remember there being some bugs with zs.param() as related to functions, but I was under the impression that that was fixed. |
|
|
|
Arde Enchanter
Joined: 09 Sep 2007 Posts: 605
|
Posted: Sat May 09, 2009 8:42 pm |
Fang Xianfu wrote: |
Also, $temp (@temp in this example) somehow contains a string as well, which is weird. |
Because it should be #ADDKEY temp %val %key (without "@"). Vartype for @temp then will show "5" (DB record), which is correct. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sun May 10, 2009 2:45 am |
Oh dear lord, I'm silly. That makes everything much easier; I've no idea why I was getting an error when I first started using the code in the OP. Back to the questions!
a) change the < on line 5 of the function to a >
b) Hmm... the easiest way to do this, I think, since you can't use %expanddb, would be to change line 3 of the alias to something like
Code: |
$result=@NSort(%dbkeys($temp))
$string=""
#forall $result {$string=%concat($string,%i," - ",%db($temp,%i),", ")}
say $string |
You can mess with the exact format of the string, but that's roughly what you're after.
c) Add another step to the above code that checks each item to see if it's 0 before it adds it to the string to be printed:
Code: |
$result=@NSort(%dbkeys($temp))
$string=""
#forall $result {#if (%i>0) {$string=%concat($string,%i," - ",%db($temp,%i),", ")}}
say $string |
I suggest putting this check in the alias rather than into the NSort function so you can use NSort for other things if you need to. |
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sun May 10, 2009 8:56 am |
Thank you for your time and effort! You have answered my questions b and c perfectly, but unfortunately changing the < to an > in the function didn't change the sort order.
And while I'm bothering you, what would be the easiest way to add to the numerical value in a database? If I have a database called colors, with red = 1, blue = 2, how would I add 1 to red with an alias? |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sun May 10, 2009 11:58 am |
That is really weird and I honestly have no idea why that isn't working. Changing the sign should be all you need to do; this simpler example works:
Code: |
test = {1251353,3453,466}
table.sort(test,function(a,b) return a < b end)
print(test) |
If you put the command line in Lua mode and enter that, then flip the < to > and do it again, the order changes.
And in answer to your second question, just do #add colors.red 1. |
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sun May 10, 2009 9:42 pm |
Thanks. I've run into a problem though. It seems if two entries in the database have the same numeric value, it will only show one of them? Is there a way to have it show two with the same value?
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Tue May 12, 2009 10:31 pm |
Any ideas? I can't seem to figure out how to make it list them if they have the same value.
|
|
|
|
chris-74269 Magician
Joined: 23 Nov 2004 Posts: 364
|
Posted: Wed May 13, 2009 12:02 am |
You could run through the code looking for duplicates, store the number of duplicates in a table, sort the table of relevance, then replace the matching variables in the sorted list with the respective number of variables in your table with the populations.
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sat May 16, 2009 8:38 am |
Ok. So I believe the issue is the '#ADDKEY' command in my alias. The help file says it replaces the object. Is there a way to make it not replace but instead create a second entry?
Code: |
LOCAL $temp
#LOOPDB @order_list {#ADDKEY $temp %val %key}
#FORALL @NSort(%dbkeys($temp)) {#WIN communication %i = %db($temp,%i)} |
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat May 16, 2009 1:46 pm |
No, you can't have two keys of a database with the same name, otherwise how would you access them both?
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat May 16, 2009 1:54 pm |
Thinking about it, though, it's a lot easier to do a sort of a table's keys by their values (which is what you're trying to do here) in Lua. All you need is something like:
Code: |
local tbl = {one = 23523, two = 464, three = 1215616}
local keys = {}
for k in pairs(tbl) do
table.insert(keys,k)
end
table.sort(keys,function (a,b) return tbl[a] > tbl[b] end) |
Which removes the necessity for making the reverse table anyway. This code will sort the key names in the keys variable by their values in the tbl table. To display them in number order, then, you do:
Code: |
for i,v in ipairs(keys) do
print(v .. " is: " .. tbl[v])
end |
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Tue May 19, 2009 11:03 am |
Ok I threw all of that into an alias? Two questions though. How do I make it sort my database, and can I have it not show the entries with zero values? Thank you for your time. I'm so close :p
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Tue May 19, 2009 3:42 pm |
Set the tbl variable to whatever you like before you run it. Eg, zs.param(1) or zs.var.whatever.
And do that check at the end:
Code: |
for i,v in ipairs(keys) do
if tbl[v] > 0 then
print(v .. " is: " .. tbl[v])
end
end |
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Fri May 22, 2009 2:12 am |
I'm sorry but I don't seem to get it. I've tried every variation I can come up with but I just don't see it. I have a database variable called COLORS, that consists of colors and numbers, ie RED = 1, BLUE = 2, GREEN = 1, ORANGE = 2, BLACK = 0. How do I get that table to be sorted high to low and not list the colors with a zero value? This is what I have as a function:
Code: |
if zs.numparam < 1 then return "" end
local tbl = zs.param(1)
for k in pairs(tbl) do
table.insert(keys,k)
end
table.sort(keys,function (a,b) return tbl[a] > tbl[b] end)
for i,v in ipairs(keys) do
if tbl[v] > 0 then
print(v .. " is: " .. tbl[v])
end
|
What should my alias look like to get it to print on the mud? Thank you for all of your help and again I'm sorry that I just don't see it. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Fri May 22, 2009 2:05 pm |
Firstly, you didn't copy the code correctly.
Code: |
if zs.numparam < 1 then return "" end
local tbl = zs.param(1)
local keys = {}
for k in pairs(tbl) do
table.insert(keys,k)
end
table.sort(keys,function (a,b) return tbl[a] > tbl[b] end)
for i,v in ipairs(keys) do
if tbl[v] > 0 then
print(v .. " is: " .. tbl[v])
end
end |
Is what you're after. This worked fine for me.
I put this code into an alias "test" and then added some keys to a variable @colors. I then did test @colors and it worked like a charm. |
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Fri May 22, 2009 11:39 pm |
Thank you very much! Now my last question is how do I get it to output it to the mud on a single line?
This was the old alias code, and I was able to use %replace on the string which was awesome:
Code: |
$result=@NSort(%dbkeys($temp))
$string=""
#forall $result {#if (%i>0) {$string=%concat($string,%i," - ",%db($temp,%i),", ")}}
#var $string %replace($string, RED, @names.RED)
say $string |
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Thu May 28, 2009 3:20 pm |
How bout just sending it to the mud in one line? Like in a say?
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Thu May 28, 2009 11:40 pm |
Sorry about that; I read this thread at work, which marked it as read, but didn't have time to write any code. Basically, you just need to build a string in the same way that script does:
Code: |
local string = ""
for i,v in ipairs(keys) do
string=string .. v .. " is " .. tbl[v] ". "
end
zs.send("say " .. string) |
This stuff is very simple in Lua; read the tutorial if you haven't already and it should make some sense of it. |
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Fri May 29, 2009 11:37 pm |
This gives me an error : Error parsing command: attempt to call field '?' (a number value) (line 11), then Stack trace:[string "code"]:11:in main chunk"
Code: |
if zs.numparam < 1 then return "" end
local tbl = zs.param(1)
local keys = {}
for k in pairs(tbl) do
table.insert(keys,k)
end
table.sort(keys,function (a,b) return tbl[a] > tbl[b] end)
local string = ""
for i,v in ipairs(keys) do
string= string .. v .. " is " .. tbl[v] ". "
end
zs.send("say " .. string) |
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Fri May 29, 2009 11:39 pm |
Realised I missed out a couple of dots between tbl[v] and ". ". It should read tbl[v] .. ". " - does that fix it?
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sat May 30, 2009 8:32 am |
Beautiful! Works great. Now the only thing left is getting it to substitute. I have been playing with zs.sub, but can't seem to figure out how to get it to substitute with values from a CMud database variable. So that in the string the RED is 8, will be JACK is 8, substituting the RED with the value of RED in a @names database variable. I was using :
Code: |
#var $string %replace($string, RED, @names.RED) |
But I can't seem to get zs.sub to work with the variable. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat May 30, 2009 3:15 pm |
#sub is used specifically in triggers to replace the text in the screen. zs.replace is the same as the %replace function, or you can use string.gsub.
|
|
|
|
cosine_omerta Wanderer
Joined: 14 Oct 2007 Posts: 50
|
Posted: Sat May 30, 2009 8:58 pm |
When I try to use any of those I get errors: Error parsing command: attempt to index global 'names' (a nil value) (line 15), and then Stack trace: [string "code"]:15:in main chunk"
Code: |
string.gsub(string, RED, names.RED) |
Names is a database variable that assigns names to the colors. RED = Frank, etc. It worked with no issue with the non lua replace function. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Sat May 30, 2009 9:04 pm |
Thinking about it, I've been a bit stupid. You shouldn't use a variable name of "string" because it overwrites the string table that contains all the string-related functions. You'll want to change that.
Secondly, strings in Lua need "" around them, so it needs to be "RED". Thirdly, the error is telling you exactly what's wrong - the global "names" you're referring to doesn't have a value, because it's a zMUD variable, not a Lua variable. You want zs.var.names.RED, which I think will work. |
|
|
|
|
|