Reading lua table with word index gives random order - lua

Following is a lua code to read a table with word indexes.
reading this into another table and printing it in output gives random order everytime it is run.
earthquakes = {
date8 = "1992/01/17",
date7 = "1971/02/09",
date6 = "2010/04/04",
date5 = "1987/10/19"
}
sf = string.format
earthquake_num ={}
for k, v in pairs(earthquakes) do
table.insert(earthquake_num, {key=k,value=v})
end
for i, v in pairs (earthquake_num) do
print(sf(" row %d key = %s", i, v.value))
end
OUTPUT :
everytime in different order

This is special feature of Lua 5.2.1 :-)
But what for this feature was introduced?
Anyway, you should not rely on ordering generated by pairs function.
EDIT :
This feature was introduced to fight hash collision attacks on web servers that are using Lua.
Randomized hash algorithm prevents easy generating of strings with equal hashes.
Ordering of table keys generated by pairs function depends on hashes of strings for string-type keys, so string keys are happened to be mixed up on every program run.

From Lua PiL on iterators:
The pairs function, which iterates over all elements in a table, is
similar, except that the iterator function is the next function, which
is a primitive function in Lua:
function pairs (t)
return next, t, nil
end
The call next(t, k), where k is a key of the table t, returns a next key
in the table, in an arbitrary order. (It returns also the
value associated with that key, as a second return value.) The call
next(t, nil) returns a first pair. When there are no more pairs, next
returns nil.
And the enumeration for next states:
next (table [, index])
The order in which the indices are enumerated is not specified,
even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.)

As Egor says the pairs iterator returns table values in an arbitrary order. To sort data and return it in a sequenced format you need to use ipairs for example
earthquakes = {
date8 = "1992/01/17",
date7 = "1971/02/09",
date6 = "2010/04/04",
date5 = "1987/10/19"
}
sf = string.format
earthquake_num ={}
for k, v in pairs(earthquakes) do
table.insert(earthquake_num, {key=k,value=v})
end
table.sort(earthquake_num,function(a, b) return a.value < b.value end)
for i, v in ipairs (earthquake_num) do
print(sf(" row %d key = %s", i, v.value))
end
see lua: iterate through all pairs in table for more information.

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"}

[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

lua - table.concat with string keys

I'm having a problem with lua's table.concat, and suspect it is just my ignorance, but cannot find a verbose answer to why I'm getting this behavior.
> t1 = {"foo", "bar", "nod"}
> t2 = {["foo"]="one", ["bar"]="two", ["nod"]="yes"}
> table.concat(t1)
foobarnod
> table.concat(t2)
The table.concat run on t2 provides no results. I suspect this is because the keys are strings instead of integers (index values), but I'm not sure why that matters.
I'm looking for A) why table.concat doesn't accept string keys, and/or B) a workaround that would allow me to concatenate a variable number of table values in a handful of lines, without specifying the key names.
Because that's what table.concat is documented as doing.
Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ยทยทยท sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string.
Non-array tables have no defined order so table.concat wouldn't be all that helpful then anyway.
You can write your own, inefficient, table concat function easily enough.
function pconcat(tab)
local ctab, n = {}, =1
for _, v in pairs(tab) do
ctab[n] = v
n = n + 1
end
return table.concat(ctab)
end
You could also use next manually to do the concat, etc. yourself if you wanted to construct the string yourself (though that's probably less efficient then the above version).

wrong lua table size when using string key index

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.

Resources