This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
sfoxdale's profile picture

Comparing Tables and Variables, and Tables in Function Parameters

Started by sfoxdale, 17 November 2012 - 10:43 AM
sfoxdale #1
Posted 17 November 2012 - 11:43 AM
Hi. I'm new to the forums, and relatively new to Lua. I mainly have experience in the very basic programming language present on the TI-83 graphing calculators.

So, jumping right in, my question is about the different ways that you can compare Tables and Variables, if any, and whether or not you can put tables into Function Parameters. I've tried different things without success and I want to know what I'm missing here, please excuse my noobishness.

My first and most important question is whether or not this is possible:


oncomd = {"open primary jail gate","open all gates","open all"}
offcomd = {"close primary jail gate","close all gates","close all"}
thor.control(oncomd,offcomd)

Would the function call take each table as an answer to each parameter or does it take all of the first tables values as the parameters? The other part is where, if that would even work above somehow, it would be compared in the actual api:


function control(oncomd,offcomd,dirc)
	if dirc == nil then
		dirc = "top"
	end
	thor.wireless()
	while true do
		_,order,_ = rednet.receive()
		if order == oncomd then
			redstone.setOutput(dirc,true)
		elseif order == offcomd then
			redstone.setOutput(dirc,false)
		end
	end
end

What this program is basically supposed to do is I want to have a computer send out orders, and other control computers turn on or off whatever they're hooked to based on the orders. But, I want them to be able to respond to multiple commands to turn on or off. It's non functioning right now as it is, and I'm frustrated, it works if I don't use tables, but I want to somehow make it where it responds to multiple commands. Can someone please help me? :/
GopherAtl #2
Posted 17 November 2012 - 11:58 AM
tables (and functions actually) are perfectly fine as parameters.

Rednet is a different matter; you can't send tables over rednet without converting them to strings first. You can do that with

--make a table
myTable={"foo"}
--make it into a string
tableAsString=textutils.serialize(myTable)

--make string back into a table
myTableCopy=textutils.unserialize(tableAsString)

as for comparing tables, no, you can't directly compare tables that way. Using == with tables will just tell you if they are the same table object, for example:

local table1={"foo"}
local table2={"foo"}

if table1==table2 then
  print("This won't happen, they're separate tables despite having the same values")
else
  print("this happens.")
end

--the exception is if you directly copy a table to a new variable
local table3=table1
--table1 and table3 are now the same actual table object
if table1==table3 then
  print("this WILL happen")
end

--note tho that changing one will change both, because they are the same table object!
table1[1]="bar"
print(table3[1]) -- will print "bar"!

to compare two tables, you'd have to iterate over the values with loops and compare them. This is easy enough if the tables are just arrays - compare the length first, then for loop from 1 to length comparing elements. For tables using key-value pairs, it's a bit more complicated.
anonimo182 #3
Posted 17 November 2012 - 12:48 PM
Can't you just use
 myTable={"foo"}
myTable2={"FOO"}
myString=textutils.serialize(myTable)
myString2=textutils.serialize(myTable2)
if myString == myString2 then
   print("no")
else
   print("yes")
?
kazagistar #4
Posted 17 November 2012 - 12:51 PM
Can't you just use
 myTable={"foo"}
myTable2={"FOO"}
myString=textutils.serialize(myTable)
myString2=textutils.serialize(myTable2)
if myString == myString2 then
   print("no")
else
   print("yes")
?
If you have more then one item in the table, then the order of the items might be different, causing the strings to be different.
anonimo182 #5
Posted 17 November 2012 - 12:55 PM
Can't you just use
 myTable={"foo"}
myTable2={"FOO"}
myString=textutils.serialize(myTable)
myString2=textutils.serialize(myTable2)
if myString == myString2 then
   print("no")
else
   print("yes")
?
If you have more then one item in the table, then the order of the items might be different, causing the strings to be different.
but you could use them! Also, I tried printing the result of textutils.serialize, and it works like: [1]foo, [2]Foo, [3]FOO, and the original table: {"foo", "Foo", "FOO"}
GopherAtl #6
Posted 17 November 2012 - 01:09 PM
hmm, using serialize to compare didn't occur to me, but I expect it work in most but not all cases. For arrays, it should work in all cases, but it'd be considerably less efficient, I think, than just looping over the array and comparing elements. For keyed tables, I'm not certain; I assume they are implemented under the hood as hash tables, so hash collisions are probably possible, and could cause lists with the same keys to have a different order, which would make them compare differently. I don't know how common hash collisions are, it depends on how luaj implements them; they could be very rare or very common.
kazagistar #7
Posted 17 November 2012 - 01:17 PM
The hash tables can have different sizes internally, which could potentially lead to different mappings as well.
Lyqyd #8
Posted 17 November 2012 - 03:06 PM
Please note that the last point in the code block of Gopher's first post in this topic is very important: A variable set to another table is actually just made into another reference to the one table. It does not create another table.

The use of textutils.serialize to compare tables will work for simple cases. Since it uses pairs(), this could break down in unexpected ways. pairs() does not guarantee anything about the order in which it iterates through key-value pairs.

Here's a relatively simple function to check the equality of all contents of a table. Cyclic tables may present a problem, though.


function compareTables(tableOne, tableTwo)
    if tableOne and tableTwo and type(tableOne) == "table" and type(tableTwo) == "table" then
        for k, v in pairs(tableOne) do
            if tableTwo[k] then
                if type(v) == "table" then
                    if not compareTables(v, tableTwo[k]) then return false end
                elseif type(v) ~= type(tableTwo[k]) then
                    return false
                else
                    if v ~= tableTwo[k] then return false end
                end
            else
                return false
            end
        end
        for k, v in pairs(tableTwo) do
            if not tableOne[k] then
                return false
            end
        end
    return true
    else
        return false
    end
end