How to find sequential items in an array using lua? - lua

I need a piece of code in lua language that can find sequential items in an array that the number of item in the group exceeds a specific nubmer. Example:if I have the array(the numbers won't be in the right order, randomly distributed)->( 2,5,9,10,11,21,23,15,14,12,22,13,24 ) ; there are two sequential groups (9,10,11,12,13,14,15) and (21,22,23,24 ) . I want the first group to be found if the specific number say (4) or more, or I can get the two groups if the number is (3) or less for example.
thanks

The logical way would seem to be to reorder the table and look for gaps in the sequences.
function table.copy(t)
local t2 = {}
for k,v in pairs(t) do
t2[k] = v
end
return t2
end
function groups(org, cnt)
-- Returns a table containing tables containing the groups found
local res = {}
local group = {}
tbl = table.copy(org) -- Prevent reordering of Original Table
table.sort(tbl)
local last = nil
for _,val in ipairs(tbl) do
if last and last + 1 ~= val then
if #group >= cnt then
table.insert(res,group)
end
group = {}
end
table.insert(group,val)
last = val
end
if #group >= cnt then
table.insert(res,group)
end
return res
end
local org = { 2,5,9,10,11,21,23,15,14,12,22,13,24 }
local result = groups(org,3)
print('Number of Groups',#result)

Related

How to select multiple random elements from a LUA table?

I'm trying to figure out how to randomly select multiple entries in a table.
This is what I have currently
local letters = {"w", "x", "y", "z"}
function randomletterselect()
local randomletters = {}
for i,v in pairs(letters) do
table.insert(randomletters,i)
end
local letter = letters[randomletters[math.random(#randomletters)]]
-- set multiple selected letters to the new table?
end
randomletterselect()
this code here works for selecting ONE random element(letter) from the table. essentially, when I run this, I want it to be multiple random letters selected. for example, one time it may select x,y another time it may be x,y,z.
The closest thing I found was honestly just what I had figured out, in this post Randomly select a key from a table in Lua
You can do...
randomletterselect=function()
local chars={}
for i=65,math.random(65,90) do
table.insert(chars,string.char(math.random(65,90)):lower())
end
print(table.concat(chars,','))
return chars
end
randomletterselect()
...for lowercase letters.
And this version returns a table without doubles...
randomletterselect=function()
local chars=setmetatable({},{__name='randomletters'})
for i=65,90 do
table.insert(chars,string.char(i):lower())
end
for i=1,math.random(#chars) do
table.remove(chars,math.random(#chars))
end
print(#chars,table.concat(chars,','))
return chars
end
local tbl = {'a', 'b', 'c', 'd'} -- your characters here
local MIN_NUM, MAX_NUM = 1, 2 ^ #tbl - 1
-- if the length of the table has changed, MAX_NUM gonna change too
math.randomseed(os.time())
local randomNum = math.random(MIN_NUM, MAX_NUM)
local function getRandomElements(num)
local rsl = {}
local cnt = 1
while num > 0 do
local sign = num % 2 -- to binary
-- if the num is 0b1010, sign will be 0101
num = (num - sign)/2
if sign == 1 then
local idx = #rsl + 1
-- use tbl[#tbl + 1] to expand the table (array)
rsl[idx] = tbl[cnt]
end
cnt = cnt + 1
end
return table.concat(rsl)
end
print(getRandomElements(randomNum))
I have another method to solve the problem, try.
MIN_NUM should be 1 cuz when its 0, getRandomElements will return an empty string

Add to table only 10 values

How i can add to table only max 10 users ?
Because i saving scoretbl in txt, and this file have more 100 lines :/ So i want save only 10 users.
I don't know how can i check there is username in the table, and don't add this user or not this username in the table and add it?
Example:
local scoretbl = {}
local num = 0
for i=1, 10 do
table.insert(scoretbl,{'Name '..i, 100 + num})
num = num + 100
end
local function AddToTable(name, score)
if table.HasValue(scoretbl,name) then return end // hmm its not work ?
table.insert(scoretbl,{name, score})
end
AddToTable('User 55', 5454)// 11 user
AddToTable('User 55', 5454)// check: only one username in table
AddToTable('User 32', 5454)// 12 user
local function ShowOnly10()
table.sort( scoretbl, function( a, b ) return a[2] > b[2] end )
//table.remove(scoretbl,#scoretbl) remove last index in table, if i need only 10 value, i need delete in cycle ?
for k, v in pairs(scoretbl) do
print(k ,v[1], v[2])
end
end
ShowOnly10()
// upd: maybe its fix username ?
local function AddToTable(name, score)
for k, v in pairs(scoretbl) do
if v[1] == name then return false end
end
table.insert(scoretbl,{name, score})
end
I recommend that you make use of Lua's hashtable, v.name and v.score are easier to read than v[1] and v[2].
The function table.HasValue does not exist. You have to write your own.
When you want to print only the first ten elements, you should only iterate over the first ten (or up to the length of the table if it is less than ten elements long).
Line comments in Lua start with --, not //.
local scoretbl = {}
for i = 1,10 do
table.insert(scoretbl, { name = 'Name '..i, score = 100*i })
end
local function AddToTable(name, score)
-- Walk the whole table to find whether a name exists
for i,v in ipairs(scoretbl) do
if v.name == name then
-- if the record is present, update it
scoretbl[i].score = score
return
end
end
-- Insert new record
table.insert(scoretbl, { name = name, score = score })
end
AddToTable('User 55', 5454) -- 11 users
AddToTable('User 55', 5454) -- check: only one username in table
AddToTable('User 32', 5454) -- 12 users
local function ShowOnly10()
table.sort(scoretbl,function(a,b) return a.score > b.score end)
for i = 1,math.min(#scoretbl,10) do
print(i, scoretbl[i].name, scoretbl[i].score)
end
end
ShowOnly10()

Lua: Merge 2 strings collections in a case-insensitive manner

I want to merge two strings collections in a case-insensitive manner:
string_collection1 = {"hello","buddy","world","ciao"}
string_collection2 = {"Hello","Buddy","holly","Bye", "bYe"}
merged_string_collection = merge_case_insensitive(string_collection1,string_collection2) --> {"hello","buddy","world","holly","bye","ciao"}
Here's an attempt, but it does not work...
function merge_case_insensitive(t1,t2)
t3 = {}
for _,s1 in pairs(t1) do
for _,s2 in pairs(t2) do
if string.lower(s1) == string.lower(s2) then
t3[s1] = s1
end
end
end
t4 = {}
i = 1
for s,_ in pairs(t3) do
t4[i] = string.lower(s)
i = i + 1
end
return t4
end
string_collection1 = {"hello","buddy","world","ciao"}
string_collection2 = {"Hello","Buddy","holly","Bye", "bYe"}
merged_string_collection = merge_case_insensitive(string_collection1,string_collection2)
for k,v in pairs(merged_string_collection) do print(k,v) end
It does not work because you use == to compare both strings which is case-sensitive.
You could do something like string.lower(s1) == string.lower(s2) to fix that.
Edit:
As you can't figure out the rest yourself, here's some code:
local t1 = {"hello","buddy","world","ciao"}
local t2 = {"Hello","Buddy","holly","Bye", "bYe"}
local aux_table = {}
local merged_table = {}
for k,v in pairs(t1) do
aux_table[v:lower()] = true
end
for k,v in pairs(t2) do
aux_table[v:lower()] = true
end
for k,v in pairs(aux_table) do
table.insert(merged_table, k)
end
merged_table now contains the lower case version of every word in both input tables.
Now pour that into a function that takes any number of input tables and you are done.
What we did here: we use the lower case version of every word in those tables and store them in a list. aux_table[string.lower("Hello")] will index the same value as aux_table[string.lower("hello")]. So we end up with one entry for each word, even if a word comes in multiple variations.
Using the keys saves us the hassle of comparing strings and distiguishing between unique words and others.
To get a table with all strings from two other tables appearing once (without regard to case), you need something like this:
function merge_case_insensitive(t1,t2)
local ans = {}
for _,v in pairs(t1) do ans[v:lower()] = true end
for _,v in pairs(t2) do ans[v:lower()] = true end
return ans
end
string_collection1 = {"hello","buddy","world","ciao"}
string_collection2 = {"Hello","Buddy","holly","Bye", "bYe"}
merged_string_collection = merge_case_insensitive(string_collection1,string_collection2)
for k in pairs(merged_string_collection) do print(k) end
Edit: And in case you want an array result (without adding another iteration)
function merge_case_insensitive(t1,t2)
local ans = {}
local
function add(t)
for _,v in pairs(t) do
v = v:lower()
if ans[v] == nil then ans[#ans+1] = v end
ans[v] = true
end
end
add(t1)
add(t2)
return ans
end
string_collection1 = {"hello","buddy","world","ciao"}
string_collection2 = {"Hello","Buddy","holly","Bye", "bYe"}
merged_string_collection = merge_case_insensitive(string_collection1,string_collection2)
for _,v in ipairs(merged_string_collection) do print(v) end
We can do this by simply iterations over both tables, and storing a temporary dictionary for checking what words we have already found, and if not there yet, putting them in our new array:
function Merge(t1, t2)
local found = {} --Temporary dictionary
local new = {} --New array
local low --Value to store low versions of words in later
for i,v in ipairs(t1) do --Begin iterating over table one
low = v:lower()
if not found[low] then --If not found yet
new[#new+1] = low --Put it in the new table
found[low] = true --Add it to found
end
end
for i,v in ipairs(t2) do --Repeat with table 2
low = v:lower()
if not found[low] then
new[#new+1] = low
found[low] = true
end
end
return new --Return the new array
end
This method eliminates the need for a third iteration, like in Piglet's answer, and doesn't keep redefining a function and closure and calling them like in tonypdmtr's answer.

Can't figure out this table arrangement

--The view of the table
local originalStats = {
Info = {Visit = false, Name = "None", Characters = 1},
Stats = {Levels = 0, XP = 0, XP2 = 75, Silver = 95},
Inventory = {
Hats = {"NoobHat"},
Robes = {"NoobRobe"},
Boots = {"NoobBoot"},
Weapons = {"NoobSword"}
}
}
local tempData = {}
--The arrangement here
function Module:ReadAll(player)
for k,v in pairs(tempData[player]) do
if type(v) == 'table' then
for k2, v2 in pairs(v) do
print(k2) print(v2)
if type(v2) == 'table' then
for k3, v3 in pairs(v2) do
print(k3) print(v3)
end
else
print(k2) print(v2)
end
end
else
print(k) print(v)
end
end
end
I'm sorry, but I can't seem to figure out how to arrange this 'ReadAll' function to where It'll show all the correct stats in the right orders.
The output is something like this:
Boots
table: 1A73CF10
1
NoobBoot
Weapons
table: 1A7427F0
1
NoobSword
Robes
table: 1A743D50
1
NoobRobe
Hats
table: 1A73C9D0
1
NoobHat
XP2
75
XP2
75
Levels
2
Levels
2
XP
0
XP
0
Here's a way to print all the elements without double or table reference values showing up.
As the name states, this function will print all the elements within a table, no matter how many nested tables there are inside it. I don't have a way to order them at the moment, but I'll update my answer if I find a way. You can also get rid of the empty spaces in the print line, I just used it so it would look neater. Let me know if it works.
function allElementsInTable(table)
for k,v in pairs(table) do
if type(table[k]) == 'table' then
print(k .. ":")
allElementsInTable(v)
else
print(" " .. k .. " = " .. tostring(v))
end
end
end
--place the name of your table in the parameter for this function
allElementsInTable(originalStats)
After more experimenting, I got this, if anyone wants it, feel free to use it.
tempData = { Info = {Visit = false, Name = 'None'},
Stats = {LVL = 0, XP = 0, Silver = 75},
Inventory = { Armors = {'BasicArmor'},
Weapons = {'BasicSword'} }
}
function Read()
for i, v in pairs(tempData['Info']) do
print(i..'\t',v)
end
----------
for i2, v2 in pairs(tempData['Stats']) do
print(i2..'\t',v2)
end
----------
for i3, v3 in pairs(tempData['Inventory']) do
print(i3..':')
for i4, v4 in pairs(v3) do
print('\t',v4)
end
end
end
Read()
Don't expect table's fields to be iterated with pairs() in some specific order. Internally Lua tables are hashtables, and the order of fields in it is not specified at all. It will change between runs, you can't have them iterated in the same order as they were filled.Only arrays with consecutive integer indices will maintain the order of their elements.

Trying to compare all entries of one table in Lua

Basically I have a table of objects, each of these objects has one particular field that is a number. I'm trying to see if any of these numerical entries match up and I can't think of a way to do it. I thought possibly a double for loop, one loop iterating through the table, the other decrementing, but won't this at some point lead to two values being compared twice? I'm worried that it may appear to work on the surface but actually have subtle errors. This is how I pictured the code:
for i = #table, 1, -1 do
for j = 1, #table do
if( table[i].n == table[j].n ) then
table.insert(table2, table[i])
table.insert(table2, table[j])
end
end
end
I want to insert the selected objects, as tables, into another pre made one without any duplicates.
Let the outer loop run over the table, and let the inner loop always start one element ahead of the outer one - this avoids double counting and comparing objects with themselves. Also, if you call the table you want to examine table that will probably hide the table library in which you want to access insert. So let's say you call your input table t:
for i = 1, #t do
for j = i+1, #t do
if( t[i].n == t[j].n ) then
table.insert(table2, t[i])
table.insert(table2, t[j])
end
end
end
Still, if three or more elements have the same value n you will add some of them multiple times. You could use another table to remember which elements you've already inserted:
local done = {}
for i = 1, #t do
for j = i+1, #t do
if( t[i].n == t[j].n ) then
if not done[i] then
table.insert(table2, t[i])
done[i] = true
end
if not done[j] then
table.insert(table2, t[j])
done[j] = true
end
end
end
end
I admit this isn't really elegant, but it's getting late over here, and my brain refuses to think of a neater approach.
EDIT: In fact... using another table, you can reduce this to a single loop. When you encounter a new n you add a new value at n as the key into your helper table - the value will be that t[i] you were just analysing. If you encounter an n that already is in the table, you take that saved element and the current one and add them both to your target list - you also replace the element in the auxiliary table with true or something that's not a table:
local temp = {}
for i = 1, #t do
local n = t[i].n
if not temp[n] then
temp[n] = t[i]
else
if type(temp[n]) == "table" then
table.insert(table2, temp[n])
temp[n] = true
end
table.insert(table2, t[i])
end
end

Resources