Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Lua ➜ Comparing two tables.

Comparing two tables.

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Falgor   (36 posts)  Bio
Date Sun 29 Jan 2017 10:05 PM (UTC)
Message
I have two tables, I want to make a code to return the differences in them (in a string, ideally).


a = {
     1 = cat
     2 = dog
     3 = bear
     4 = beaver
     }

b = {
     1 = cat
     2 = dog
     3 = bear
     4 = beaver
     5 = ox
     }

I want to the function to return key 5 from table B into a string.
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #1 on Sun 29 Jan 2017 10:49 PM (UTC)

Amended on Mon 30 Jan 2017 07:36 PM (UTC) by Fiendish

Message
You're very unspecific about whether you care about ordering of the result or how you want it to look, so here's one approach of many to get you started:

[EDIT]I've edited this to show that it works

a = {
     "cat",
     "dog",
     "elephant",
     "bear",
     "beaver"
     }

b = {
     "cat",
     "dog",
     "bear",
     "beaver",
     "ox"
     }

a_inverse = {}
b_inverse = {}
differences = {}

for k,v in ipairs(a) do
   a_inverse[v] = k
end

for k,v in ipairs(b) do
   if a_inverse[v] == nil then
      print(v,"is only in table b")
   end
   b_inverse[v] = k
end

> ox     is only in table b

for k,v in ipairs(a) do
   if b_inverse[v] == nil then
      print(v,"is only in table a")
   end
end

> elephant     is only in table a

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #2 on Mon 30 Jan 2017 08:29 AM (UTC)
Message
This works perfectly thank.

All I'm going to do now is add an if function to show output if something has changed.


if differences == nil then
else
tprint (differences)


I'll have a crack at it when I get in from work.
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #3 on Mon 30 Jan 2017 10:08 AM (UTC)

Amended on Mon 30 Jan 2017 10:11 AM (UTC) by Fiendish

Message
Since differences is defined already it will never be nil. You'll want


if #differences ~= 0 then
   tprint(differences)
end

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #4 on Mon 30 Jan 2017 05:58 PM (UTC)
Message
Meh, I'm tying myself in knots here. I'm not even sure this is the best way to approach this.

What I'm making is a log on/log off function that compares 2 lists, and prints differences:


Bear has logged in.

Bear has logged out.


Would I be better off making 2 strings and removing the duplicates from those, rather than messing around with tables? I just wanted to use tables because they are slightly more efficient and seem the 'right' way to do things.
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #5 on Mon 30 Jan 2017 07:04 PM (UTC)
Message
for k,v in ipairs (wholist) do
a_inverse[v] = k
end

for k,v in ipairs (oldwholist) do
if a_inverse[v] == nil then
print(v .. " logged out.")
end
b_inverse[v] = k
end

for k,v in ipairs (wholist) do
if b_inverse[v] == nil then
print(v .. " logged in.")
end
end


So i'm nearly there! This works one way, but not the other. It is displaying "logged in" messages, which means it is successfully finding the difference when a new value is added to the "wholist" table, but doesn't show my "logged out" messages (when wholist loses a value).
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #6 on Mon 30 Jan 2017 07:36 PM (UTC)
Message
Perhaps the problem is your lists. I've edited my previous post to show that it does work in both directions.

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #7 on Mon 30 Jan 2017 07:43 PM (UTC)

Amended on Mon 30 Jan 2017 07:50 PM (UTC) by Falgor

Message
Perhaps it is because my list has numerical keys?

I make my list like so


for player in string.gmatch(page, "title...(%w+)")
do
wholist [ i ] = "" .. player
i = i + 1
end


therefore my "wholist" table looks like this


1="Bear"
2="Beaver"
3="Ox"
4="Elephant


At the very start of my code (before the above function) I do the following to populate the "oldwholist" table


oldwholist = {}
oldwholist = wholist


Therefore by the time I come to compare the tables I have them both populated, and if someone logs out, they will be present on "oldwholist" but not on "wholist". When someone logs in, the reverse is true, I think my logic is sound. Just trying to unlearn Zuggsofts scripting language, I've relied too heavily on FORALL functions :)
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #8 on Mon 30 Jan 2017 07:58 PM (UTC)
Message
Falgor said:

Perhaps it is because my list has numerical keys?


All lists have numeric keys unless otherwise specified.

{"bear", "dog", "pig"}
is the same as
{[1]="bear", [2]="dog", [3]="pig"}

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #9 on Mon 30 Jan 2017 08:04 PM (UTC)

Amended on Mon 30 Jan 2017 08:10 PM (UTC) by Fiendish

Message
Falgor said:

At the very start of my code (before the above function) I do the following to populate the "oldwholist" table


oldwholist = {}
oldwholist = wholist



This is likely your problem. Table variables in Lua are only references, meaning they only point to some location in memory and are not the table objects themselves. There is some table object somewhere in memory, but your wholist variable isn't actually the table. It's just a memory address.
So you think you're cloning the table there, but you're not. All you're doing is making the oldwholist variable point at the same location in memory as the wholist variable. That doesn't duplicate. That makes them the same and any future actions will modify both variables.

Try this to demonstrate the problem for yourself:

a = {"a","b","c"}
b = {"d","e","f"}

for i,v in ipairs(a) do
   print(i,v)
end
for i,v in ipairs(b) do
   print(i,v)
end

a = b

print(a)
print(b)

a[2] = "HELLO"

for i,v in ipairs(a) do
   print(i,v)
end
for i,v in ipairs(b) do
   print(i,v)
end




Try this instead...


require "copytable" -- table copying module included with MUSHclient
oldwholist = copytable.deep(wholist)

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #10 on Mon 30 Jan 2017 08:47 PM (UTC)

Amended on Mon 30 Jan 2017 09:17 PM (UTC) by Falgor

Message
Okay. Here is the complete code and a break down of how it works. I've modified how "oldwholist" gets its content to make sure that both tables are working how they should.

I know a lot of this should be in separate functions, but I'm very new to Lua so getting it working first before I neaten it all up and put it in a plugin.

Firstly, I grab the data from my MUD's website to get it ready to break down into the 'wholist' table.


if not http then http = require("socket.http") end
local mysocket = require("socket.http")
mysocket.TIMEOUT = 2
local page = http.request("http://www.t2tmud.org/who.php") 


Next I use gmatch to strip out the names of the online Players from all the API data, these names are put into the "wholist" table.


local player = {}
i = 1
for player in string.gmatch(page, "title...(%w+)")
do
wholist [ i ] = "" .. player
i = i + 1
end


I then run the ipairs/foreach/if functions to see if "wholist" is different to "oldwholist", to see if someone has logged in or out, changes are sent to Output. I'm aware this won't work the first time the script is run, as it needs to run twice to populate both "wholist" and "oldwholist".


for k,v in ipairs (wholist) do
a_inverse[v] = k
end

for k,v in ipairs (oldwholist) do
if a_inverse[v] == nil then
print(v .. " logged out.")
end
b_inverse[v] = k
end

for k,v in ipairs (wholist) do
if b_inverse[v] == nil then
print(v .. " logged in.")
end
end


Next I use the same function as earlier to populate "oldwholist" from the websites data, this means that on the next cycle, "wholist" will be updated before "oldwholist", allowing the above comparing function to work.


i = 1
for player in string.gmatch(page, "title...(%w+)")
do
oldwholist [ i ] = "" .. player
i = i + 1
end


Finally I turn the "wholist" table into a string and send it to a miniwindow.


wholistfinal = table.concat (wholist, ",")
win = "win_" .. GetPluginID ()
WindowCreate (win, 0, 0, 2000, 33, miniwin.pos_top_left, 0, ColourNameToRGB("navy"))
WindowFont (win, "f", "Courier New", 10, true, false, false, false)
WindowText (win, "f", wholistfinal,
            2, 0, 0, 0, 
            ColourNameToRGB ("white"), 
            false)
WindowShow (win, true)



About 5% of the time, I get the correct log on/off messages, despite the miniwindow changing correctly each time someone logs in or out. I'm currently running this in a timer, it will end up in a loop in a plugin. Also the [ i ] aren't typos, they where turning everything italic.

Thanks for any help or tips to help me neaten the whole code up.
Top

Posted by Fiendish   USA  (2,537 posts)  Bio   Global Moderator
Date Reply #11 on Mon 30 Jan 2017 10:44 PM (UTC)
Message
I'll test later if you don't manage to get it working. In the meantime, though...

why do you do
"" .. player
?

Also, do you empty your lists before repopulating them?

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Falgor   (36 posts)  Bio
Date Reply #12 on Mon 30 Jan 2017 10:52 PM (UTC)
Message
I literally solved it as you posted that!

I've been messing around so much with populating the "oldwholist", I totally forgot that I removed to line to clear the "wholist".

Works perfectly!

Thanks so much, now it's time to turn each bit into a separate function so it looks smoother and get it sent to a plugin!

(once I figure out miniwindow wordwrapping!)
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


31,754 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.