Attempt to index nested table and insert numeric character number - insert

local file = assert(io.open("E:\\text.txt","r"))
local Table = {}
local function Sort()
for c in file:lines() do
Table[#Table + 1] = {}
print(c)
for i = 1,#c do
Table[#Table][i] = string.byte(c,i,i)
Table[#Table] = table.concat(Table[#Table])
end
print("hi")
print(table.concat(table))
end
end
Sort()
-- error:8: attempt to index a string value(field '?')
This Lua code is supposed to traverse through the lines of the file and create a table with the numeric representation of all its characters.

In your outer loop the first time through you set Table[1] = {}. The first time through your inner loop you are setting Table[1] to the result of table.concat which is a string. The next time through the inner loop when i=2 you are attempting Table[1][2], but Table[1] is now a string, hence the error.

Related

Returning the last return values of an iterator without storing a vararg in a table

Writing a function that takes a generic for loop iterator consisting of the iterator function, the invariant state & the loop control variable to return the value the control variable has in the last iteration is straightforward:
function iterator_last_value(iterator, state, control_var)
local last
for value in iterator, state, control_var do
last = value
end
return last
end
print(iterator_last_value(("hello world"):gmatch"%a+")) -- world
This could be easily extended to support arbitrary constant numbers of arguments up to Lua's local register limit. We can also add vararg iterator return value support by always storing the last vararg in a table; this requires us to get rid of Lua's for loop syntactic sugar:
function iterator_last(iterator, state, control_var)
local last = {}
local last_n = 0
local function iter(...)
local control_var = ...
if control_var == nil then
return table.unpack(last, 1, last_n)
end
last = {...}
last_n = select("#", ...)
return iter(iterator(state, control_var))
end
return iter(iterator(state, control_var))
end
print(iterator_last(ipairs{"a", "b", "c"})) -- 3, c
which works well but creates a garbage table every iteration. If we replace
last = {...}
last_n = select("#", ...)
with
last_n = select("#", ...)
for i = 1, last_n do
last[i] = select(i, ...)
end
we can get away with reusing one table - presumably at the cost of manually filling the table using select being less efficient than {...}, but creating significantly fewer garbage tables (only one garbage table per call to iterator_last).
Is it possible to implement a variadic return value iterator_last without storing a vararg with significant overhead using a table, coroutine or the like, leaving it on the stack and only passing the varargs around through function calls? I conjure that this is not possible, but have been unable to prove or disprove it.

How can I add minutes and seconds to a datetime in lua?

I have a lua function to attempt to convert the time duration of the currently playing song e.g. hh:mm:ss to seconds.
function toSeconds (inputstr)
local mytable = string.gmatch(inputstr, "([^"..":".."]+)");
local conversion = { 60, 60, 24}
local seconds = 0;
--iterate backwards
local count = 0;
for i=1, v in mytable do
count = i+1
end
for i=1, v in mytable do
mytable[count-i]
seconds = seconds + v*conversion[i]
end
return seconds
end
in order to add it to os.time to get the estimated end time of a song.
but the hours may be missing, or the minutes may be missing on a short track.
When running against https://www.lua.org/cgi-bin/demo All I get is input:10: 'do' expected near 'in'
for the test script
function toSeconds (inputstr)
local mytable = string.gmatch(inputstr, "([^"..":".."]+)");
local conversion = { 60, 60, 24}
local seconds = 0;
--iterate backwards
local count = 0;
for i=1, v in mytable do
count = i+1
end
for i=1, v in mytable do
mytable[count-i]
seconds = seconds + v*conversion[i]
end
return seconds
end
print(toSeconds("1:1:1")
You're mixing up the two possible ways of writing a for loop:
a)
for i=1,10 do
print(i, "This loop is for counting up (or down) a number")
end
b)
for key, value in ipairs({"hello", "world"}) do
print(key, value, "This loop is for using an iterator function")
end
The first one, as you can see, simply counts up a number, i in this case. The second one is very generic and can be used to iterate over almost anything (for example using io.lines), but is most often used with pairs and ipairs to iterate over tables.
You also don't write for ... in tab, where tab is a table; you have to use ipairs for that, which then returns an iterator for the table (which is a function)
You're also using string.gmatch incorrectly; it doesn't return a table, but an iterator function over the matches of the pattern in the string, so you can use it like this:
local matches = {}
for word in some_string:gmatch("[^ ]") do
table.insert(matches, word)
end
which gives you an actual table containing the matches, but if you're only going to iterate over that table, you might as well use the gmatch loop directly.
for i=1, v in mytable do
count = i+1
end
I think you're just trying to count the elements in the table here? You can easily get the length of a table with the # operator, so #mytable
If you have a string like hh:mm:ss, but the hours and the minutes can be missing, the easiest thing might be to just fill them with 0. A somewhat hacky but short way to achieve this is to just append "00:00:" to your string, and look for the last 3 numbers in it:
local hours, minutes, seconds = ("00:00:"..inputstr):match("(%d%d):(%d%d):(%d%d)$")
If nothing is missing, you'll end up with something like 00:00:hh:mm:ss, which you only take the last 3 values of to end up with the correct time.

iterating over a table passed as an argument to a function in lua

I am trying using the for _ in pairs() notation to iterate over a table within a function, but if I type anything, even gibberish like print('asdgfafs'), nested inside the for loop, it never gets printed. Code:
record = {bid1,bid2,bid3}
bid1 = {bidTime = 0.05,bidType = 'native'}
bid2 = {bidTime = 0.1,bidType = 'notNative'}
bid3 = {bidTime = 0.3,bidType = 'native'}
function getBids(rec,bidTimeStart,bidTimeFinish,bidType,numberOfBids)
wantedBids = {}
bidCount = 0
for i,v in pairs(rec) do
print('asdfasdfasdfa')
print(i .. ' + ' .. v)
end
end
getBids(record,0,1,'native',5)
Can anyone tell me why and suggest a workaround?
You are creating the record table before creating the bid# tables.
So when you do record = {bid1, bid2, bid3} none of the bid# variables have been created yet and so they are all nil. So that line is effectively record = {nil, nil, nil} which, obviously, doesn't give the record table any values.
Invert those lines to put the record assignment after the bid# variable creation.

How to create the equivalent of a HashMap<Int, Int[]> in Lua

I would like to have a simple data structure in lua resembling a Java HashMap equivalent.
The purpose of this is that I wish to maintain a unique key 'userID' mapped against a set of two values which get constantly updated, for example;
'77777', {254, 24992}
Any suggestions as to how can I achieve this?
-- Individual Aggregations
local dictionary = ?
-- Other Vars
local sumCount = 0
local sumSize = 0
local matches = redis.call(KEYS, query)
for _,key in ipairs(matches) do
local val = redis.call(GET, key)
local count, size = val:match(([^:]+):([^:]+))
topUsers(string.sub(key, 11, 15), sumCount, sumSize)
-- Global Count and Size for the Query
sumCount = sumCount + tonumber(count)
sumSize = sumSize + tonumber(size)
end
local result = string.format(%s:%s, sumCount, sumSize)
return result;
-- Users Total Data Aggregations
function topUsers()
-- Do sums for each user
end
Assuming that dictionary is what you are asking about:
local dictionary = {
['77777'] = {254, 24992},
['88888'] = {253, 24991},
['99999'] = {252, 24990},
}
The tricky part is that the key is a string that can't be converted to a Lua variable name so you must surround each key with []. I can't find a clear description of rule for this in Lua 5.1 reference manual, but the Lua wiki says that if a key "consists of underscores, letters, and numbers, but doesn't start with a number" only then does it not require the [] when defined in the above manner, otherwise the square brackets are required.
Just use a Lua table indexed by userID and with values another Lua table with two entries:
T['77777']={254, 24992}
This is possible implementation of the solution.
local usersTable = {}
function topUsers(key, count, size)
if usersTable[key] then
usersTable[key][1] = usersTable[key][1] + count
usersTable[key][2] = usersTable[key][2] + size
else
usersTable[key] = {count, size}
end
end
function printTable(t)
for key,value in pairs(t) do
print(key, value[1], value[2])
end
end

Add objects to array in ruby loop persists latest object to all array items

The following code demonstrates a ruby (1.8.7) for loop in which a column and header read in from excel are saved as an object (object attributes: header=string, contents=array of strings). As I'm reading in several columns I want to save them as an array of objects.
The issue is that each loop, while incrementing the array 'matrix', and successfully storing the new object, seems to overwrite the previous elements of the matrix array with the newest object. When I iterate through the finished array, I just get x instances of the same object.
column_count = count_columns(worksheet)
row_count = count_rows(worksheet)
matrix = Array.new
#i don't think header needs to be an array in the below loop, but anyway...
header = Array.new
contents = Array.new
for column in 0..column_count - 1
header[column] = worksheet.Cells(1, column + 2).Value
for row in 0..row_count
contents[row] = worksheet.Cells(row + 2, column + 2).Value
end
matrix[column] = Worksheet_Column.new(header[column], contents)
end
#looping after the array was created puts the same information in each iteration
for column in 0..matrix.length - 1
puts "loop = #{column}"
puts matrix[column]
end
Well, I still don't see what elementary mistake allowed the contents to write backward, but having noticed the problem occurred for the contents and not for the header this solution has been successful.
for column in 0..column_count - 1
contents[column] = Array.new
header[column] = worksheet.Cells(1, column + 2).Value
for row in 0..row_count
contents[column][row] = worksheet.Cells(row + 2, column + 2).Value
end
matrix[column] = Worksheet_Column.new(header[column], contents[column])
end

Resources