wrong lua table size when using string key index - lua

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.

Related

why is table.remove and in pairs function both not working in Roblox Studio?

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

Table sorting index names LUA [duplicate]

I have gone through many questions and Google results but couldn't find the solution.
I am trying to sort a table using table.sort function in Lua but I can't figure out how to use it.
I have a table that has keys as random numeric values. I want to sort them in ascending order. I have gone through the Lua wiki page also but table.sort only works with the table values.
t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
I want it like:
t = { [7]="qwe", [23]="fgh", [223]="asd", [543]="hjk" }
You cannot set the order in which the elements are retrieved from the hash (which is what your table is) using pairs. You need to get the keys from that table, sort the keys as its own table, and then use those sorted keys to retrieve the values from your original table:
local t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
local tkeys = {}
-- populate the table that holds the keys
for k in pairs(t) do table.insert(tkeys, k) end
-- sort the keys
table.sort(tkeys)
-- use the keys to retrieve the values in the sorted order
for _, k in ipairs(tkeys) do print(k, t[k]) end
This will print
7 qwe
23 fgh
223 asd
543 hjk
Another option would be to provide your own iterator instead of pairs to iterate the table in the order you need, but the sorting of the keys may be simple enough for your needs.
What was said by #lhf is true, your lua table holds its contents in whatever order the implementation finds feasible. However, if you want to print (or iterate over it) in a sorted manner, it is possible (so you can compare it element by element). To achieve this, you can do it in the following way
for key, value in orderedPairs(mytable) do
print(string.format("%s:%s", key, value))
end
Unfortunately, orderedPairs is not provided as a part of lua, you can copy the implementation from here though.
The Lua sort docs provide a good solution
local function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end
Then you traverse the sorted structure
local t = { b=1, a=2, z=55, c=0, qa=53, x=8, d=7 }
for key,value in pairsByKeys(t) do
print(" " .. tostring(key) .. "=" .. tostring(value))
end
There is no notion of order in Lua tables: they are just sets of key-value pairs.
The two tables below have exactly the same contents because they contain exactly the same pairs:
t = { [223] = "asd" ,[23] = "fgh",[543]="hjk",[7]="qwe"}
t = {[7]="qwe",[23] = "fgh",[223] = "asd" ,[543]="hjk"}

How can I get the number of times an enttry in a table was listed

I need to find a way to see how many times an entry is listed in a table.
I have tried looking at other code for help, and looking at examples online none of them help
local pattern = "(.+)%s?-%s?(.+)"
local table = {"Cald_fan:1", "SomePerson:2", "Cald_fan:3","anotherPerson:4"}
for i,v in pairs(table) do
local UserId, t = string.match(v, pattern)
for i,v in next,UserId do
--I have tried something like this
end
end
it is suppose to say Cald_fan was listed 2 times
Something like this should work:
local pattern = "(.+)%s*:%s*(%d+)"
local tbl = {"Cald_fan:1", "SomePerson:2", "Cald_fan:3","anotherPerson:4"}
local counts = {}
for i,v in pairs(tbl) do
local UserId, t = string.match(v, pattern)
counts[UserId] = 1 + (counts[UserId] or 0)
end
print(counts['Cald_fan']) -- 2
I renamed table to tbl (as using table variable makes the table.* functions not available) and fix the pattern (you had unescaped '-' in it, while your strings had ':').
If the format of your table entries is consistent, you can simply split the strings apart and use the components as keys in a map of counters.
It looks like your table entries are formatted as "[player_name]:[index]", but it doesn't look like you care about the index. But, if the ":" will be in every table entry, you can write a pretty reliable search pattern. You could try something like this :
-- use a list of entries with the format <player_name>:<some_number>
local entries = {"Cald_fan:1", "SomePerson:2", "Cald_fan:3","anotherPerson:4"}
local foundPlayerCount = {}
-- iterate over the list of entries
for i,v in ipairs(entries) do
-- parse out the player name and a number using the pattern :
-- (.+) = capture any number of characters
-- : = match the colon character
-- (%d+)= capture any number of numbers
local playerName, playerIndex = string.match(v, '(.+):(%d+)')
-- use the playerName as a key to count how many times it appears
if not foundPlayerCount[playerName] then
foundPlayerCount[playerName] = 0
end
foundPlayerCount[playerName] = foundPlayerCount[playerName] + 1
end
-- print out all the players
for playerName, timesAppeared in pairs(foundPlayerCount) do
print(string.format("%s was listed %d times", playerName, timesAppeared))
end
If you need to do pattern matching in the future, I highly recommend this article on lua string patterns : http://lua-users.org/wiki/PatternsTutorial
Hope this helps!

[lua]: Key with value 1 doesnt do the same as regular 1

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

Why is this function to add the contents of a table together in Lua returning nothing

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()).

Resources