Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » CMUD General Discussion Goto page 1, 2  Next
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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)}
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)

Last edited by Fang Xianfu on Sun May 10, 2009 2:32 am; edited 1 time in total
Reply with quote
Arde
Enchanter


Joined: 09 Sep 2007
Posts: 605

PostPosted: 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.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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?
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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?
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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.
Reply with quote
chris-74269
Magician


Joined: 23 Nov 2004
Posts: 364

PostPosted: 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.
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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)}
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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?
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: Thu May 28, 2009 3:20 pm   
 
How bout just sending it to the mud in one line? Like in a say?
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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)
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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?
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
cosine_omerta
Wanderer


Joined: 14 Oct 2007
Posts: 50

PostPosted: 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.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: 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.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » CMUD General Discussion All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net