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

Naming tables automatically in a function

Started by CountJankula, 07 June 2013 - 08:41 PM
CountJankula #1
Posted 07 June 2013 - 10:41 PM
Hi Pros,

I am trying to make a program that will build something (a circle or sphere for now) by:
1. defining the coordinates at which to place a block and storing these in a table.
2. calling on those tables to place blocks.

I want to generate the names of tables automatically because I don't know ahead of time how many I will need (Also, it seems like a cool thing to do). I think it then makes sense to generate the names again when I want to access a particular table.

However, I don't know what I doing and it isn't working (I bet you are surprised). I know that the way I am defining and calling on my tables is wrong, but I don't know how to fix it. Please help. Also if you have a better idea on how to store and recall coordinates in a table, that would be greatly appreciated.



function domeQuadrantTables(rad)
--make a table for each layer of quarter dome with x, y coordinates. x, y, and z are positive.
for j = 0, rad do
  if j < round(math.sqrt((rad^2)/3)) then
   for i = 0, round(math.sqrt(rad^2/2)) do
    z = j
    y = i
    x = round(math.sqrt(rad^2 - y^2 - z^2))
    if y >= x then
	 limit = y
	 for i = limit, 0, -1 do
	  z = j
	  x = i
	  y = round(math.sqrt(rad^2 - x^2 - z^2))
	  xy = x .. "," .. y
	  tablename = "ztable" .. z
	  tablename = {}
	  table.insert(tablename, xy)
	 end
	 break
    end
    xy = x .. "," .. y
    tablename = "ztable" .. z
    tablename = {}
    table.insert(tablename, xy)
   end
  else
   for x = round(math.sqrt((2 * rad^2)/3)), 0, -1 do
    for y = 0, round(math.sqrt((2 * rad^2)/3)) do
	 z = round(math.sqrt(rad^2 - x^2 - y^2))
	 if z == j then
	  xy = x .. "," .. y
	  tablename = "ztable" .. z
	  tablename = {}
	  table.insert(tablename, xy)
	 end
    end
   end 
  end
end
end
function buildFromTable(rad)
--Reads ztables and builds a quarter dome according to coordinates, layer by layer, bottom up.
--To make a shpere there would be 1 loop for each quarter of a dome, 8 loops total.
--The sign of the x, y, z coordinates and the order of reading from ztables would be changed accordingly in each loop.
for j = 0, rad do
  tablename = "ztable" .. j
  print(tablename)
  for i = 1, table.maxn(tablename) do
   xy = tablename[i]
   local xytable = {}
   for part in string.gmatch(xy, "[^,]+") do
    table.insert(xytable, part)
   end
   x = tonumber(xytable[1])
   y = tonumber(xytable[2])
   z = j
   navigateToZ(x, y, z)
   placeBlock()
   table.remove(xytable[1])
   table.remove(xytable[2])
  end
end
end
Lyqyd #2
Posted 08 June 2013 - 02:41 AM
Split into new topic.

Tables don't have names. Tables can be the value of one or more variables, but there is nothing requiring tables to have any "name" at all.

What you should probably do instead is use a table of tables, and simply use numeric indices for the subtables. This will be far simpler in the long run.
CountJankula #3
Posted 08 June 2013 - 01:45 PM
Ok, I think I get that.
How would I initialize a table so that the values of that table are themselves tables? And do it for some arbitrary number of indexes?


for i = 1, x do
  multiTable = {i={}}
end

doesn't seem like it would work
Symmetryc #4
Posted 08 June 2013 - 02:21 PM
I think this is what you're looking for:

multiTable = setmetatable({}, {__index = function(self, key) return {} end})
It makes every single index of "multiTable" automatically a table, no matter what number it is.
Engineer #5
Posted 08 June 2013 - 03:21 PM
I think this is what you're looking for:

multiTable = setmetatable({}, {__index = function(self, key) return {} end})
It makes every single index of "multiTable" automatically a table, no matter what number it is or key.
It can be done waaay easier. You are deep into metatables, arent you?
Here for example:

local maintable = {}
for i = 1, 5 do
   maintable[#maintable + 1] = {}
end

--[[
#<table-name> returns the length of the table. When we do +1, we create a new index and set the value to a new table. 

Essentially we are doing this:
local maintable = {
  [1] = {};
  [2] = {};
  [3] = {};
  [4] = {};
  [5] = {};
}
If you really wanted, you can overwrite indexes or create them:
for i = 1, 5 do
   maintable[i] = {}
end
]]
Edited on 08 June 2013 - 01:28 PM
Symmetryc #6
Posted 08 June 2013 - 06:04 PM
I think this is what you're looking for:

multiTable = setmetatable({}, {__index = function(self, key) return {} end})
It makes every single index of "multiTable" automatically a table, no matter what number it is or key.
It can be done waaay easier. You are deep into metatables, arent you?
Here for example:

local maintable = {}
for i = 1, 5 do
   maintable[#maintable + 1] = {}
end

--[[
#<table-name> returns the length of the table. When we do +1, we create a new index and set the value to a new table. 

Essentially we are doing this:
local maintable = {
  [1] = {};
  [2] = {};
  [3] = {};
  [4] = {};
  [5] = {};
}
If you really wanted, you can overwrite indexes or create them:
for i = 1, 5 do
   maintable[i] = {}
end
]]
I don't really see how this is easier, mine is one line of code that affects all indices, yours is multiple lines of code that only affects a
limited amount of indices. Also, instead of thing[#thing+1]={} you can do table.insert(thing, {})
CountJankula #7
Posted 08 June 2013 - 06:12 PM
Thank you both Lua Maniac and Scripter.

These both look like cool solutions to me. I will try each out when I can and report back with what will likely be spectacular failure (I can't wait).

Cheers and thanks again.
LBPHacker #8
Posted 08 June 2013 - 06:23 PM
For future reference, the names are in the blue lines above the avatar. I bet your name is not "clueless"…
CountJankula #9
Posted 08 June 2013 - 09:07 PM
I don't know about that LBPHacker. … I'll just show myself out.
Orwell #10
Posted 08 June 2013 - 09:11 PM
If in the future you really want to give variables arbitrary names, you can do:

local name = "variable"
_G[name] = 42
print(variable) -- prints 42
This is usually not a good idea though (and indeed not what you need here).
Bomb Bloke #11
Posted 08 June 2013 - 10:29 PM
I don't really see how this is easier, mine is one line of code that affects all indices, yours is multiple lines of code that only affects a limited amount of indices.

The catch is your method ALWAYS affects all indexes. So as soon as you try to pull stuff out of those tables it makes, it instead returns yet another fresh, empty table… That is to say, although all indexes act as tables, you can't store anything in them.

I like the idea behind it, though I'm not entirely sure I understand how it works. Best I can make out (without actually going off and looking up what metatables are), every time you try to refer to an index from the table it instead runs that function, so there's no way to have it actually KEEP those tables it's churning out without it inserting them into another table somewhere (if they're not already in there - you'd need to check for that) and then returning a pointer to the relevant one.

Also, instead of thing[#thing+1]={} you can do table.insert(thing, {})

For what little it's worth, table.insert executes just a little bit more slowly. Or a lot more slowly, depending on your implementation.
theoriginalbit #12
Posted 08 June 2013 - 10:35 PM
If in the future you really want to give variables arbitrary names, you can do:

local name = "variable"
_G[name] = 42
print(variable) -- prints 42
This is usually not a good idea though (and indeed not what you need here).
Or this works too, either way…

local n = 'name'
getfenv()[ n ] = { 'test' }
print( name[1] )

Symmetryc #13
Posted 08 June 2013 - 10:48 PM
I don't really see how this is easier, mine is one line of code that affects all indices, yours is multiple lines of code that only affects a limited amount of indices.

The catch is your method ALWAYS affects all indexes. So as soon as you try to pull stuff out of those tables it makes, it instead returns yet another fresh, empty table… That is to say, although all indexes act as tables, you can't store anything in them.

I like the idea behind it, though I'm not entirely sure I understand how it works. Best I can make out (without actually going off and looking up what metatables are), every time you try to refer to an index from the table it instead runs that function, so there's no way to have it actually KEEP those tables it's churning out without it inserting them into another table somewhere (if they're not already in there - you'd need to check for that) and then returning a pointer to the relevant one.

Also, instead of thing[#thing+1]={} you can do table.insert(thing, {})

For what little it's worth, table.insert executes just a little bit more slowly. Or a lot more slowly, depending on your implementation.
__index basically sets the default value for the indices of a table. Usually If you haven't defined an index, it is just nil, but of you have the __index metamethod, you can change this to whatever you want, in this case a table. It doesn't affect indices whose values are already set though. Admittedly, I haven't actually tested this as I'm using my iPod and won't have access to a computer for a while…

Edit: Now that I reread it, it appears that you've already tested it? I'm sorry I cant see it too well through the mobile safari, it reloads the page randomly… If so, try this:

local t = setmetatable({}, {__index = function()
return setmetatable({}, {__newindex = function(self, key, value) self[key] = value end})
end})
If that doesn't work, then I don't know :/.
Bomb Bloke #14
Posted 08 June 2013 - 11:04 PM
I was assuming it worked like that, but the problem is you're setting the "default value" to a function that returns an empty table. As opposed to a function that sets the value of the specified index to an empty table, before returning that. (Yes, I pasted it into a CC computer to test what it did.)

I'm also not strictly sure what happens if you overwrite a function with something while that function is running, but again, I'd be interested in seeing if this could be made to work.
Lyqyd #15
Posted 09 June 2013 - 05:08 AM
Ok, I think I get that.
How would I initialize a table so that the values of that table are themselves tables? And do it for some arbitrary number of indexes?


for i = 1, x do
  multiTable = {i={}}
end

doesn't seem like it would work

That's sort of what you want to do:


local multiTable = {}
for i = 1, 4 do
    table.insert(multiTable, {})
end

You then have a table of tables indexed from multiTable[1] through multiTable[4]. This will be much easier than all of the stuff they're talking about above.

Guys, if you want to have a discussion of metatables, please take it elsewhere. It's orthogonal to this question, and it's really not helping to have that discussion in this topic.
Kingdaro #16
Posted 09 June 2013 - 07:29 AM
This works just as well:


local multiTable = {}
for i=1, 4 do
  multiTable[i] = {}
end

Insertion logic here is complicating the process a little bit.
Symmetryc #17
Posted 09 June 2013 - 10:52 AM
Ok, I think I get that.
How would I initialize a table so that the values of that table are themselves tables? And do it for some arbitrary number of indexes?


for i = 1, x do
  multiTable = {i={}}
end

doesn't seem like it would work

That's sort of what you want to do:


local multiTable = {}
for i = 1, 4 do
    table.insert(multiTable, {})
end

You then have a table of tables indexed from multiTable[1] through multiTable[4]. This will be much easier than all of the stuff they're talking about above.

Guys, if you want to have a discussion of metatables, please take it elsewhere. It's orthogonal to this question, and it's really not helping to have that discussion in this topic.
Sorry, the OP said that they wanted it to affect arbitrary amounts of indices and I immediately thought of meta tables :P/>
Lyqyd #18
Posted 09 June 2013 - 02:58 PM
Kingdaro, it does indeed. Good point.

Symmetryc, OP seems to just now be getting to tables within tables. Metatables isn't the best thing to throw at them. :P/>
CountJankula #19
Posted 09 June 2013 - 03:08 PM
So, I am trying the solution offered and I am failing at inserting data into the tables.

after running either of these:

mZt = {}
for i = 1, 5 do
  table.insert(mZt, {})  --lyqyd
end

or


mZt = {}
for i = 1, 5 do
  mZt[#mZt + 1] = {} --Engineer
end

I should have:

mZt = {
  [1] = {};
  [2] = {};
  [3] = {};
  [4] = {};
  [5] = {};
}

That makes sense to me. Now I want to insert data into these tables in an ordered manner.
table.insert(mZt, index, data) would seem like the thing to do.

Can index be a variable that evaluates to an integer within the range of tables that we made earlier? like so?


for j = 0, 5 do
  for i = 0, round(math.sqrt(5^2/2)) do
   z = j
   y = i
   x = round(math.sqrt(5^2 - y^2 - z^2))
   data = x .. "," .. y
   index = j + 1
   table.insert(mZt, index, data)
  end
end


What I expect to happen here is that when the outer loop (j) starts data will be placed in mZt[1] until the (i) loop finishes. Then data will be placed in mZt[2] until the (i) loop finishes, and so on.

I should be about to:

print(mZt[1][1])
print(mZt[1][2])
print(mZt[1][3])

and get something like:

5,0
5,1
5,2

Instead I get a bunch of blank spaces. So I know that at least one of my many expectations is wrong. Please tell me which ones and how to fix them.

thank you.

More code if you want it:
Spoiler

local tArgs = {...}
local rad = tArgs[1]
function round(num)
if num >= 0 then
  return math.floor(num+.5)
else
  return math.ceil(num-.5)
end
end
function domeQuadrantTables(rad)
--make a table for each layer (z axis) of a quarter of a dome with an ordered set of x, y coordinates. x, y, and z are positive.
mZt = {}
for i = 0, rad do
  --mZt[i] = {}   --Enginner and Kingdaro
  --mZt[#mZt + 1] = {} --Enginner
  table.insert(mZt, {})  --lyqyd
end
for j = 0, rad do
  if j < round(math.sqrt((rad^2)/3)) then
   for i = 0, round(math.sqrt(rad^2/2)) do
	z = j
	y = i
	x = round(math.sqrt(rad^2 - y^2 - z^2))
	if y >= x then
	 for i = y-1, 0, -1 do
	  z = j
	  x = i
	  y = round(math.sqrt(rad^2 - x^2 - z^2))
	  xy = x .. "," .. y
	  index = j + 1
	  table.insert(mZt, index, xy)
	 end
	 break
	end
	xy = x .. "," .. y
	index = j + 1
	table.insert(mZt, index, xy)
   end
  else
   for x = round(math.sqrt((2 * rad^2)/3)), 0, -1 do
	for y = 0, round(math.sqrt((2 * rad^2)/3)) do
	 z = round(math.sqrt(rad^2 - x^2 - y^2))
	 if z == j then
	  xy = x .. "," .. y
	  index = j + 1
	  table.insert(mZt, index, xy)
	 end
	end
   end
  end
end
end
Symmetryc #20
Posted 09 June 2013 - 07:15 PM
Instead of table.insert, use t[index] = data.
CountJankula #21
Posted 09 June 2013 - 08:22 PM
using t[index] = data results in the data in the table being overwritten as the loop… loops. so only the last result is saved. This is not the intended result.

Holy shit.
I think I got it:

table.insert(mZt[index], xy)
Spoiler

function domeQuadrantTables(rad)
--make a table for each layer (z axis) of a quarter of a dome with an ordered set of x, y coordinates. x, y, and z are positive.
mZt = {}
for i = 0, rad do
  --mZt[i] = {}   --Enginner and Kingdaro
  --mZt[#mZt + 1] = {} --Enginner
  table.insert(mZt, {})  --lyqyd
end
for j = 0, rad do
  if j < round(math.sqrt((rad^2)/3)) then
   for i = 0, round(math.sqrt(rad^2/2)) do
	z = j
	y = i
	x = round(math.sqrt(rad^2 - y^2 - z^2))
	if y >= x then
	 for i = y-1, 0, -1 do
	  z = j
	  x = i
	  y = round(math.sqrt(rad^2 - x^2 - z^2))
	  xy = x .. "," .. y
	  index = j + 1
	  table.insert(mZt[index], xy)
	  -- mZt[index] = table.insert(index, xy)
	  -- mZt[index] = xy --Symmetryc
	  --table.insert(mZt, index, xy)
	  -- mZt[j][#j + 1] = xy
	 end
	 break
	end
	xy = x .. "," .. y
	index = j + 1
	table.insert(mZt[index], xy)
	-- mZt[index] = xy --Symmetryc
	-- table.insert(mZt, index, xy)
	-- mZt[j][#j + 1] = xy
   end
  else
   for x = round(math.sqrt((2 * rad^2)/3)), 0, -1 do
	for y = 0, round(math.sqrt((2 * rad^2)/3)) do
	 z = round(math.sqrt(rad^2 - x^2 - y^2))
	 if z == j then
	  xy = x .. "," .. y
	  index = j + 1
	  table.insert(mZt[index], xy)
	  -- mZt[index] = table.insert(index, xy)
	  -- mZt[index] = xy --Symmetryc
	  -- table.insert(mZt, index, xy)
	  -- mZt[j][#j + 1] = xy
	 end
	end
   end
  end
end
end

And I can print all the results out with:
Spoiler

for i = 1, rad + 1 do
for j = 1, table.maxn(mZt[i]) do
  print(mZt[i][j])
end
end
Edited on 09 June 2013 - 06:34 PM