I'm currently attempting to create a table of tables, and removing parts from the previous nested table to make the next nested table, thereby decreasing the length of each nested table by 1.
However, upon running the code below, it triggers a bad argument #1 to 'remove' (got string, expected table) error. I can't understand why this is.
possiblePorts = {}
possiblePorts[1] = {"VGA","USB","Ethernet","9mm","HDMI"}
for i=2,5 do
possiblePorts[i] = table.remove(possiblePorts[i-1],math.random(1,5))
end
I'm expecting it to create a table of:
possiblePorts = {
{"VGA","USB","Ethernet","9mm","HDMI"},
{"VGA","Ethernet","9mm","HDMI"},
{"VGA","9mm","HDMI"},
{"9mm","HDMI"},
{"9mm"}
} --formatted for simple viewing
or something similar - why is it not doing so, and what can I do to fix it?
table.remove will return the removed element not the remaining elements of the table.
Lua 5.3 Reference Manual #table.remove
What happens in your code is the first loop works with no issues.
During the second loop, possiblePorts[i-1] is now 2 so we attempt to use table.remove on the value at index 2. The value we put at index 2, in the first loop, was a string so we generate the error trying to pass it as the first arg of table.remove.
You also cannot use math.random(1,5) on each table as that gives you a risk of hitting outside the end of the array, and this will result in an error from table.remove. You want to change 5 out for the length of the array.
This code does what you were trying to accomplish
local possiblePorts = {}
possiblePorts[1] = {"VGA","USB","Ethernet","9mm","HDMI"}
for i=2,5 do
possiblePorts[i] = {}
local skip = math.random(1,#possiblePorts[i-1]) -- Get value we will skip at random
local index = 0 -- Index for new array
for j=1,#possiblePorts[i-1] do -- Loop over all the elements of that last array.
if j ~= skip then -- If the value is not the one we are skipping add it.
index = index + 1
possiblePorts[i][index] = possiblePorts[i-1][j]
end
end
end
for k,v in ipairs(possiblePorts) do
print(k, "{" .. table.concat(v," ") .. "}")
end
Output:
1 {VGA USB Ethernet 9mm HDMI}
2 {USB Ethernet 9mm HDMI}
3 {USB Ethernet HDMI}
4 {Ethernet HDMI}
5 {Ethernet}
Related
I have the following code which Roblox Developer and the Lua.org manual both say should work to remove an instance from the table so I can store as a local, but the local is only holding a nil value.
The table is there. It shows up on the print function. It just will not store to be useful in the app.
I have tried multiple versions of this code including going with just the pairs function, just the table.remove function, and going with and without the position for the table remove, and it all generates nil variable.
response = HttpService:GetAsync(mining)
data = HttpService:JSONDecode(response, Enum.HttpContentType.ApplicationJson)
local function tprint(t)
for k,v in pairs(t) do print(k,v) end
end
tprint(data)
local a = table.remove(data, 4)
local b = table.remove(data, 3)
local c = table.remove(data, 2)
local d = table.remove(data, 1)
The solution ended up being so simple, and yet so profound. I can now use this to link crypto, bank accounts, credit cards, and anything else I want directly into Roblox or any other lua based program.
a = (data["result"]["amount"])
Before I dig into the error you're seeing, first some background information.
Lua tables have two methods of indexing values: numerically, and by keys. Often times you will see these two different methods be used to describe the kind of data structure that uses it.
Arrays and lists are tables that use numeric keys to index information.
local arr = {}
arr[1] = "abc"
arr[2] = 123
arr[3] = true
-- print the length of the array
print(#arr) -- 3
-- print the contents of the array
for i, v in ipairs(arr) do
print(i, v)
-- 1 abc
-- 2 123
-- 3 true
end
On the other side of things, dictionaries and hash maps and associative arrays use keys to store information :
local dict = {}
dict["foo"] = "abc"
dict["bar"] = 123
dict["blah"] = true
dict["katz"] = { 1, 2, 3 }
-- print the number of numerical keys in the dictionary
print(#dict) -- 0
-- print the contents of the dictionary
for k, v in pairs(dict) do
print(k, v)
-- foo abc
-- bar 123
-- blah true
-- katz table
end
While lua allows a table to use both of these indexing methods simultaneously, it's important never to mix the two, as behaviors can get real funky when you do. When a table has keys, treat it like a dictionary. When a table has numerical indices, treat it like an array.
When you use HttpService to decode a JSON string into a table, it generates a dictionary that reflects the heirarchical structure of the original data.
The table library, which you call with table.insert() and table.remove() expects that the table you're working with is an array.
When your data is arranged like this :
local data = {}
data["Success"] = true
data["StatusCode"] = 200
data["StatusMessage"] = "Success"
data["Headers"] = {} -- a dictionary of headers
data["Body"] = {
result = {
amount = 1,
depositAddress = "blah",
},
} -- after HttpService:JSONDecode() is called...
And you tell it to remove a numbered index with table.remove(data, 4), it won't work because there's no data stored at index number 4. data is a dictionary, not an array.
Often, it is annoying to try to print out the contents of a table with multiple layers of data, especially JSON tables, as the pairs function will only index one level at a time. Thankfully, Roblox's print function and Output widget are smart enough to do this for you. You can simply print(data) and it will show you the full table in the output and allow you to inspect each level.
Then once you know how your data is structured you can step through it value by value.
local amount = data["Body"]["result"]["amount"]
-- or
local amount = data.Body.result.amount
Ive been coding for a mod Im making for a game but I ran into an issue with tables not returning values when the key is entered:
for k, v in pairs(self.math) do
print(self.exce[1])
print(self.exce[k])
print(k)
if self.exce[k] ~= nil then
self.math[k] = nil
end
end
This is the specific part of the script that is breaking. When I run these in the game it returns:
[lua]: true
[lua]: nil
[lua]: 1
Which means is basically saying that 1 is not equal to 1.
The function I used to store my data is
function filterExceptions.server_onException( self, id )
if self.exce[id] == nil then
self.exce[id] = true
self.network:sendToClients( "client_onList", id )
else
self.exce[id] = true
self.network:sendToClients( "client_offList", id )
end
end
In this code the self is a table made by the game you can acces and get game data from or store it in and the id comes from a function I made to get the players id. This id in this case is a 1 (I printed it multiple times).I know that every part of this code is working except for the code in the first block, and escpecialy the part where it tries to do self.exce[k]. Ive tried a lot like going trough every variable in self.exce to see if it was in there and then do stuff, but it still wouldn't work. Its very annoying how lua thinks that k ~= 1 while it definitely is, ive even used similar code in a part that is working.
So what is wrong about this code that its not printing the self.exce[k] while self.exce[1] does work? Dont worry about the creation of the table and stuff, cuz that is already happening whenever it is needed, else it would have given errors about that too.
Putting together a couple different comments and your code here, it looks like the index value of the array in some particular iteration of the "for in pairs" loop (or perhaps all of them, but I'll touch on that in a minute) is a string instead of an integer.
To summarize if you don't want to read the entire thing, "for k, v in pairs" loops will iterate through an entire array, setting k to the index of the value v. It appears your "for in pairs" loop is attempting to iterate through a value of nil where k is a string instead of an integer. You may also want to look into using ipairs instead of pairs in your for loop.
The value of someArray[1]is different than the value of someArray["1"].
The index [1] is a completely different index than the index ["1"] for any given array.
A simple fix would be to use
ind = tonumber(k)
print(self.exce[ind])
This converts the string k to a number type. Be aware this may throw an error if k is a non-numerical string. If the array has any values where the index is a non-numerical string, you may get an error. As the other answer suggests, converting the index k to a string instead of an integer would work as well, and would not throw errors if you used a non-numerical value for your indices.
My guess as to why this is happening would be that the function that you're using to store your data to an array, filterExceptions.server_onException( self, id ), is being passed a string instead of an integer, which would result in the k value being set to a string in that particular iteration of the "for in pairs" loop.
To help better understand this, here's a bit of example code:
a = {true, false, false}
a[1] = true
a["1"] = true
print("Raw for in pairs loop")
for k, v in pairs (a) do
print(type(k)..k)
end
print("For in pairs converting k to a number")
for k, v in pairs (a) do
ind = tonumber(k)
print(type(ind)..ind)
end
print("For in ipairs")
--which I'm not sure I completely understand but
--it seems to skip over any iteration where k is not a number
for k, v in ipairs(a) do
print(type(k)..k)
end
This code produces the following output:
Raw for in pairs loop
number1
number2
number3
string1
For in pairs converting k to a number
number1
number2
number3
number1
For in ipairs
number1
number2
number3
EDIT: Not sure what's going on in the self.math table so I can't comment on that.
EDIT2: I'd also refer you to the following link: lua: iterate through all pairs in table
The top answer there should help understand the difference between pairs and ipairs, if you don't already. You may want to use ipairs to prevent values of k where v == nil from being iterated through with pairs. pairs will iterate through every key/value pair, whereas ipairs will iterate through integer keys starting at 1 and going until it hits a nil value.
EDIT3: I'm sorry this is such a long answer...I just wanted to be thorough.
It apears converting the id to a string fixes this, tough im still confused as to why this same code worked on another block and not this one.
function filterExceptions.server_onException( self, id )
local id2 = tostring(id)
if self.exce[id2] == nil then
self.exce[id2] = true
self.network:sendToClients( "client_onList", id )
else
self.exce[id2] = true
self.network:sendToClients( "client_offList", id )
end
end
I am stuck trying to make the contese of a table (all integers) add together to form one sum. I am working on a project where the end goal is a percentage. I am putting the various quantities and storing them in one table. I want to then add all of those integers in the table together to get a sum. I haven't been able to find anything in the standard Library, so I have been tyring to use this:
function sum(t)
local sum = 0
for k,v in pairs(t) do
sum = sum + v
end
return sum
However, its not giving me anything after return sum.... Any and all help would be greatly appreciated.
A more generic solution to this problem of reducing the contents of a table (in this case by summing the elements) is outlined in this answer (warning: no type checking in code sketch).
If your function is not returning at all, it is probably because you are missing an end statement in the function definition.
If your function is returning zero, it is possible that there is a problem with the table you are passing as an argument. In other words, the parameter t may be nil or an empty table. In that case, the function would return zero, the value to which your local sum is initialized.
If you add print (k,v) in the loop for debugging, you can determine whether the function has anything to add. So I would try:
local function sum ( t ) do
print( "t", t ) -- for debugging: should not be nil
local s = 0
for k,v in pairs( t ) do
print(k,v) --for debugging
s = s + v
end
return s
end
local myTestData = { 1, 2, 4, 9 }
print( sum( myTestData) )
The expected output when running this code is
t table: [some index]
1 1
2 2
3 4
4 9
16
Notice that I've changed the variable name inside the function from sum to s. It's preferable not to use the function name sum as the variable holding the sum in the function definition. The local sum in the function overrides the global one, so for example, you couldn't call sum() recursively (i.e. call sum() in the definition of sum()).
The following is part of a script I use to indicate which items (in this case, MOBs in a MUD) are not in my tabled database.
if mqtable[1] == nil then
Note("No mobs missing from database!")
else
if "%1" ~= "" then
mindex = "%1"
mdesc = mqtable[tonumber(mindex)]
end
if "%2" ~= "" then mlvl = "%2" end
if "%3" ~= "" then mkeyw = "%3" end
if not mindex and mqtable[1] then
tprint(mqtable)
elseif mindex and not mlvl then
Note(mdesc)
elseif mindex and mlvl and not mkeyw then
Note("Syntax is: mqmob [index] [level] [keywords]")
else
mobtable[mdesc]={level = mlvl, keywords = mkeyw}
table.save(mobtable,savepath.."/Mobs/"..areazone..".tbl")
Note(mqtable[tonumber(mindex)] .. " saved. Level: ".. mlvl .. " -- Keywords: " .. mkeyw)
table.remove(mqtable, tonumber(mindex))
mobtable = table.load(savepath .. "/Mobs/" .. areazone .. ".tbl")
mlvl, mkeyw, mdesc = nil, nil, nil
end
Assume all undefined functions are working as intended and do not appear to be the root cause. "%1", "%2", and "%3" are passed parameters through a trigger. Essentially, if this were a function, those three parameters would be called as foo(blah, bleh, blargh).
Problem
If I type mqmob (which fires the above script), it displays within the room which MOBs have not been added to my table. I then use mqmob <index> <level> <keyword> to add the mob to that table. Once that has been done, however, the script refuses to work, and regardless of the number of items that were originally on the table, mqmob returns nil. Why is the table being completely wiped after storing one bit of information?
Example
I look in a room and see the following:
A rat dwells here.
A mouse chases after some cheese.
A spider makes its home in the corner.
A flea leaps about playfully.
Say that I have only A spider makes its home in the corner. in the database. The remaining three descriptions are placed into mqtable, and when I call mqmob, it displays:
1="A rat dwells here."
2="A mouse chases after some cheese."
3="A flea leaps about playfully."
Now, I type mqmob 1 20 rat to create mobtable["A rat dwells here."] with {level = 20, keywords = rat}. But once I do that, if I type mqmob again, it returns nil.
Explanation of variables
mobtable is merely a table that contains the mob's description as the key, and its corresponding level and keywords as values. For example:
mobtable = {"A rat nibbles on some cheese." = {keyword = "rat", level = 20}}
mqtable is populated only when there is no corresponding match in mobtable. Essentially, the trigger fires, compares to keys in mobtable, and if not found, populates mqtable. This is to help prevent me from unnecessary work of adding mobs already in mobtable.
The problem I keep running into is that I will add one mob, but when I run the print command a second time, it returns nil. However, I can still add and view the individual indexes in mqtable. It just doesn't seem able to print it up anymore.
Usually for getting table size, the standard table library function # operator works.
However when I make a table which has a string key index, it doesn't work.
local function addWriterIdListToTable()
local returnTable = {}
local requestString = "1234:16 5678:8 9012:1"
local idList = requestString:split(" ")
for i,v in ipairs(idList) do
local oneId = v:split(":")
returnTable[oneId[1]] = oneId[2]
end
for k,v in pairs(returnTable) do
print (k .. " " .. v)
end
print("size of table: " .. #returnTable)
return returnTable
end
I want to trsnform a string to table.
The function "split" parse a string, split it with parameter as a delimiter, and return as table.
The result of a excution above function like below.
1234 16
9012 1
5678 8
size of table: 0
It shows the content of table exactly as I expected, but its count is not.
Anybody to help me?
Thanks in advance.
The # operator tells you the highest numeric index in the table. If there are any gaps in the numeric indexing, it may return the highest below the gap. Basically, the # operator only works right if you're treating your table like a dense array.
If you actually want to know how many entries are in a table, you'll need to iterate over it using the pairs() function and count how many items you get.
function countTableSize(table)
local n = 0
for k, v in pairs(table) do
n = n + 1
end
return n
end
Although I do wonder why you even need to know how many entries are in the table. Typically all you care about is if the table is empty or not, and you can check that by just seeing if next(table) == nil.