How to get the latest x entries of a table in Lua? - lua

If I have (for example) a table with 300 entries, how would I get the latest x entries only?
I was thinking of doing the next, but I'm wondering if there is a better/more optimized way to do this exact thing.
local TestTable = {}
-- Populate table
for i = 1, 300, 1 do
print('Adding: ' .. i)
table.insert(TestTable , i)
end
-- Get latest x of table
function GetLatestFromTable(OriginalTable, Amount)
local TableLength = #OriginalTable
local Retval = {}
for i = 1, Amount, 1 do
if TableLength - i <= 0 then break end -- Dont allow to go under 0
table.insert(Retval, OriginalTable[TableLength - i])
print("Adding to Retval: " .. OriginalTable[TableLength - i] .. ' (Index: ' .. TableLength - i .. ')')
end
return Retval
end
print(#TestTable)
local LatestTable = GetLatestFromTable(TestTable, 10)
print(#LatestTable)

For keys in sequence (and values are string/number) a call to table.concat() allows range parameter.
local tab = {"One", "Two", "Three", "Four", "Five"}
print(table.concat(tab, '\n', #tab - 1, #tab)) -- Last two entries
See: table.concat()

As mentioned by #Luke100000, one way could be to use Lua custom iterators. In Lua, an iterator is a special function which, when called, will return the next value. It is made possible by the fact that functions are first-class citizen in Lua and they can refer to previous scope with a mecanism named closure.
To answer the question, one could start implement a general iterator over a given range.
function IterateRange (Table, Min, Max)
local ClosureIndex = Min - 1
local ClosureMax = math.min(Max, #Table)
local function Closure ()
if (ClosureIndex < ClosureMax) then
ClosureIndex = ClosureIndex + 1
return Table[ClosureIndex]
end
end
return Closure
end
IterateRange is a function returning an anonymous function. The anonymous function does not take any parameter. It simply update the ClosureIndex index defined in the local scope of IterateRange and return the table value.
The first thing that the anonymous function do is to increment ClosureIndex. For that reason, ClosureIndex must be initialized to Min - 1.
This function works as one might expect:
TestTable = {}
for i = 1, 300, 1 do
print('Adding: ' .. i)
table.insert(TestTable , i)
end
for Value in IterateRange(TestTable, 290, 300) do
print(Value)
end
290
291
292
293
294
295
296
297
298
299
300
Now, it's trivial to reuse this general iterator to iterate over the last N entries of a given table:
function IterateLastEntries (Table, Count)
local TableSize = #Table
local StartIndex = (TableSize - Count)
return IterateRange(Table, StartIndex, TableSize)
end
It also work as one might expect:
TestTable = {}
for i = 1, 300, 1 do
print('Adding: ' .. i)
table.insert(TestTable , i)
end
for Value in IterateLastEntries(TestTable, 10) do
print(Value)
end
290
291
292
293
294
295
296
297
298
299
300
And finally, to summarize all this in a fully copy & pasteable solution:
TestTable = {}
for i = 1, 300, 1 do
print('Adding: ' .. i)
table.insert(TestTable , i)
end
function IterateRange (Table, Min, Max)
local ClosureIndex = Min - 1
local ClosureMax = math.min(Max, #Table)
local function Closure ()
if (ClosureIndex < ClosureMax) then
ClosureIndex = ClosureIndex + 1
return Table[ClosureIndex]
end
end
return Closure
end
function IterateLastEntries (Table, Count)
local TableSize = #Table
local StartIndex = (TableSize - Count)
return IterateRange(Table, StartIndex, TableSize)
end
for Value in IterateLastEntries(TestTable, 10) do
print(Value)
end
This should return:
290
291
292
293
294
295
296
297
298
299
300
I will let the OP update the code in order to achieve the same results for 30 entries.

Related

Stack Overflow on Lua metatable

I used to have a construct that worked with luajit:
mytbl = setmetatable({1}, {__index = function(tbl,idx) return tbl[idx - 1] + 1 end})
Now with plain Lua 5.4 this gives me a stack overflow:
> mytbl[1000]
stdin:1: C stack overflow
stack traceback:
stdin:1: in metamethod 'index'
....
The goal is to have a table where the default is to return the index itself:
mytbl[10]
should return 10. But when I say
mytbl[3] = 5
the value of
mytbl[10]
should be 12 (the values from 1 now yield 1,2,5,6,7,8,9,10,11,12,...)
Is there a way to get this in Lua 5.4 without the stack overflow? Or should I create another function for it?
You are accessing the table within the __index. That causes another __index to be called and so on.
Use rawget when you want to access the tbl itself.
If you want to get a custom logic that does not rely on existence of elements, write your function in a way that allows for trailing recursion or write it iteratively without any recursion at all:
__index=function(tbl, idx)
local acc = 0
for i=idx-1, 1, -1 do
local th = rawget(tbl, i)
if th then
return acc + th + 1
else
acc = acc + 1
end
end
return acc
end
This is what I came up with now:
__index=function(tbl, idx)
local max = 0
for k, v in next, tbl do
if k <= idx then max = v - k end
end
return idx + max
end
I only have very few entries in tbl so this should be reasonable fast for my purposes.
My test:
mytbl[5] = 9
for i = 1, 10 do
print(mytbl[i])
end
outputs
1
2
3
4
9
10
11
12
13
14

finding minimum values from a cut table Lua 5.1.5

I have a Lua script that turns a table into segments:
function tablecut(t, n)
local result = {}
local j = 0
for i = 1, #t do
if (i-1) % n == 0 then
j = j + 1
result[j] = {}
end
result[j][#result[j]+1] = t[i]
end
return result
end
output = tablecut({'15', '62', '14', '91', '33', '55', '29', '4'}, 4)
for i = 1, #output do
for j = 1, #output[i] do
io.write(tostring(output[i][j])..' ')
end
print()
end
output:
15 62 14 91
33 55 29 4
And I am trying to find the minima from the cut lists so the output would look like this:
15 62 14 91
min = 14
33 55 29 4
min = 4
Edit: If its of any importance this is how I got it to work on Lua 5.3 but there is no table.move function on Lua 5.1. I can't remember how my thought function worked when I wrote this code.
function indexOf(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
Indicies = {}
Answers = {}
function chunks(lst, size)
local i = 1
local count = 0
return function()
if i > #lst then return end
local chunk = table.move(lst, i, i + size -1, 1, {})
i = i + size
count = count + 1
return count, chunk
end
end
local a = {91,52,19,59,38,29,58,11,717,91,456,49,30,62,43,8,17,15,26,22,13,10,2,23} --Test list
for i, chunk in chunks(a, 4) do
x=math.min(a)
print(string.format("#%d: %s", i, table.concat(chunk, ",")))
table.sort(chunk)
print(math.min(chunk[1]))
table.insert(Answers, chunk[1])
table.insert(Indicies, (indexOf(a, chunk[1])))
Output:
#1: 91,52,19,59
19
#2: 38,29,58,11
11
#3: 717,91,456,49
49
your table cut function could be simplified, and your output for loop needs you use an iterator if you want to get an output simply like you do in your 5.3 script.
function cuttable(t,n)
local binned = {}
for i=1,#t,n do
local bin = {}
for j=1,n do
table.insert(bin, t[i + ((j - 1) % n)])
end
table.insert(binned, bin)
end
return binned
end
For the for loop, we can use ipairs on the output of cuttable keeping things pretty simple, then we just do the same steps of concat then sort and print out our results.
for k, bin in ipairs(cuttable(a,4)) do
local output = "#" .. k .. ":" .. table.concat(bin, ",")
table.sort(bin)
print(output)
print(bin[1])
end
Output
#1:91,52,19,59
19
#2:38,29,58,11
11
#3:717,91,456,49
49
#4:30,62,43,8
8
#5:17,15,26,22
15
#6:13,10,2,23
2
One way to implement the cutting would be using a for loop & unpack. I have handled the case of the length not being divisible by 4 after the for loop to (1) maximize performance (check doesn't need to be done every iteration) and (2) be able to directly pass the values to math.min, which doesn't accept nils.
for i = 1, math.floor(#t / 4), 4 do
print(unpack(t, i, i+4))
print("min = " .. math.min(unpack(t, i, i+4)))
end
-- If #t is not divisible by 4, deal with the remaining elements
local remaining = #t % 4
if remaining > 0 then
print(unpack(t, #t - remaining, remaining))
print("min = " .. math.min(unpack(t, #t - remaining, remaining)))
end

Lua math.floor return wrong value

.There is my code:
for k,v in pairs(result) do
result[k] = math.floor(v*1000)/1000
if k == 215 then
print(v, math.floor(v*1000))
end
end
for k,v in pairs(extra) do
extra[k] = math.floor(v*1000)/1000
end
Where
result[215] = 113
But when I run it by C++ Lua-Tinker, I get the print:
113, 112999
It's very confusing!
Thank to Egor Skriptunoff, I got the answer.
There is an exmple:
local num1 = 100 + 1300/100
print(num1, math.floor(num1))
local num2 = (1 + 13/100) * 100
print(num2, math.floor(num2))
And the result is:
113 113
113 112
Actually, the num2 = 112.9999999999999..., because of the 13/100.But when use 'print' to show it, there is a round action:
local a=112.99999999999 --(the count of 9 is 11)
print(a)
local b=112.999999999999 --(the count of 9 is 12)
print(b)
the result is:
112.99999999999
113

Lua #Table returning 0, despite Table containing 3 elements (tables)? [duplicate]

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

How to get number of entries in a Lua table?

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

Resources