I'm writing a lua script, and one of the things it does is copy a table into a table of tables, and apply a couple transformations to it. What's odd though is when i go to use one of those tables later (and modify some of it's properties), changes will also seem to show up in other tables! Code:
-- thanks to http://stackoverflow.com/questions/1283388/lua-merge-tables/1283608#1283608
-- tableMerge:
-- merges two tables, with the data in table 2 overwriting the data in table 1
function tableMerge(t1, t2)
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
tableMerge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
--tableCopy:
--takes a table and returns a complete copy including subtables.
function tableCopy(t)
return tableMerge({}, t)
end
local t1 = { a = 1, b = true, c = "d", e = { f = 2 } }
local t2 = tableCopy(t1)
t2.b = false
t2.e.f = 1
print(t1.b) -- prints true as it should
print(t1.e.f) -- prints 1!
[removed other code for reasons of the information it contains, and this a good reproduction of the bug]
so is it a bug in my code or something? i can't figure it out....
This is how Lua tables work - they don't get copied around, only references to the tables are passed to functions or stored in tables instead. If you are familiar with .NET terminology, you could say that tables are "reference types". Observe:
function modtable(t)
t.hello = "world"
end
local t = { hello = "no!"; }
modtable(t)
print(t.hello)
This prints "world" because the modtable function gets a reference to the table and not a copy. The same thing happens when you try to store table in another table
local t = { hello = "no!"; }
local bigT = { innerTable = t; }
bigT.innerTable.hello = "world"
print(t.hello)
t.hello = "double world";
print(bigT.innerTable.hello);
This will print
world
double world
because t and bigT.innerTable are essentially the same table.
If you want copies of the tables that you can modify independently from one-another you can write a small function to duplicate a table
function deep_copy_table(t)
local result = {}
for k,v in pairs(t)
do
if (type(v) == "table")
then
result[k] = deep_copy_table(v)
else
result[k] = v
end
end
return result
end
local t = { hello = "no!"; }
local bigT = { innerTable = deep_copy_table(t); }
bigT.innerTable.hello = "world"
print(t.hello)
t.hello = "double world";
print(bigT.innerTable.hello);
This will print "no!" and "world" - t and bigT.innerTable are different tables now.
OK, sorry for the double answer - the previous answer is still good, although it's an answer to a different question.
I spotted the problem in your code, it's the tableMerge function as expected:
if type(v) == "table" then
if type(t1[k] or false) == "table" then
tableMerge(t1[k] or {}, t2[k] or {})
else
t1[k] = v -- this is the problematic line
end
else
So, if t1[k] is not a table, you just assign v to it and you end up with a reference to v instead of a copy. This effectively makes your tableCopy function shallow copy instead of deep copy. Since you are overwriting t1[k] anyway, this seems like a good implementation of the tableMerge function:
function tableMerge(t1, t2)
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k]) ~= "table" then -- if t1[k] is not a table, make it one
t1[k] = {}
end
tableMerge(t1[k], t2[k])
else
t1[k] = v
end
end
return t1
end
This should hopefully fix the problem at hand.
Some other random thoughts on your code, if you don't mind:
in the original implementation of mergeTable: type(t1[k] or false). The t1[k] or false trickery is pointless here, type() can handle nil values just fine (it will return "nil" for nil)
t2[k] can never be nil. Tables in Lua cannot contain nil as a value, pairs() will never return a pair with nil as key or value. The t2[k] or false is again kind of pointless.
I spotted this line near the end of the first script: table.remove(v.Weapons). I'm guessing you need second parameter for the call to table.remove
Oh, and one final piece of advice: don't just drop 200 lines of code and expect people to debug it for you - no one will bother. Try to narrow down the problematic code. You already suspected the tableMerge function, if you had taken it out by itself and ran a simple test on it you would have spotted the problem.
Happy coding!
Related
Let's say that I want to store some alphanumeric data. I can either use a table:
t = { "a", "b", "c" }
or a string:
s = "abc"
When I want to test if 'b' is in my data set, I can test the table by saying:
function findInTable(table, element)
for i, v in ipairs(table) do
if v == element then return true end
end
return false
end
if findInTable(t, "b") then
--do stuff
or I can test the string by saying:
if s:find("b") then
--do stuff
Which of these methods is faster? I imagine that string.find is essentially doing the same thing as my findInTable function. I need to check data in this way on every draw for a game, so performance is critical. A lot of my data is being extracted from text files and it's easier to keep it in string format rather than using commas or some such as delimiters to organize it into table values.
Consider doing this:
t = { ["a"]=true, ["b"]=true, ["c"]=true }
Then to test if a string s is in t, simply do
if t[s] then ...
I do similar things between two frames in LÖVE [love2d].
And without benchmarking it i can say: Its fast enough
( Frames decreases with many drawable objects only )
Moreover i would like to add the table functions to the table t as methods...
t = setmetatable({"a", "b", "c"}, {__index = table})
print(t[t:concat():find("b")])
-- Output: b
-- False Output: nil
-- And nil never happens if...
print(t[t:concat():find("d")] or t[#t])
-- Output: c
-- ..fallback to a default with: or
...check it out or change this in...
https://www.lua.org/demo.html
...to figure out how it works.
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.
In my imperative-style Scala code, I have an algorithm:
def myProcessor(val items: List) {
var numProcessed = 0
while(numProcessed < items.size) {
val processedSoFar = items.size - numProcessed
numProcessed += processNextBlockOfItems(items, processedSoFar)
}
}
I would like to keep the "block processing" functionality, and not just do a "takeWhile" on the items list. How can I rewrite this in functional style?
You need to change it to a recursive style wherein you "pass" in the "state" of each loop
#tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
case Nil => count
case x :: xs =>
processNextBlockOfItems(items, count)
myProcessor(xs, count + 1)
}
assuming that "processedSoFar" is not an index. If you can work with the current "head" of the list:
#tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
case Nil => count
case x :: xs =>
process(x)
myProcessor(xs, count + 1)
}
where process would only process the current "head" of the List.
So, this depends on what you consider to be more functional, but here's a version without the 'var'
def myProcessorFunctional(items: List[Int]) {
def myProcessorHelper(items: List[Int], numProcessed: Int) {
if (numProcessed < items.size) {
val processedSoFar = items.size - numProcessed
myProcessorHelper(items,
numProcessed + processNextBlockOfItems(items, processedSoFar))
}
}
myProcessorHelper(items, 0)
}
(making it a list of Ints just for simplicity, it would be easy to make it work with a generic List)
I have to say it's one of those cases where I don't mind the mutable variable - it's clear, no reference to it escapes the method.
But as I said in a comment above, processNextBlockOfItems is inherently non-functional anyway, since it's called for its side effects. A more functional way would be for it to return the state of its processing so far, and this state would be updated (and returned) on a subsequent call. Right now, if you in the middle of processing two different items lists, you'd have the issue of maintaining two different partially-processed states within processNextBlockOfItems...
Later:
Still ignoring the state issue, one convenient change would be if processNextBlockOfItems always processed the first block of the items list passed to it, returned the remaining items it had not processed (this is convenient and efficient if using List, so much so I'm wondering why you're using indicies).
This would yield something like:
def myProcessorMoreFunctional(items: List[Int]) {
if (!items.isEmpty) {
myProcessorMoreFunctional(processNextBlockOfItems(items))
}
}
I have a function that takes a variable amount of ints as arguments.
thisFunction(1,1,1,2,2,2,2,3,4,4,7,4,2)
this function was given in a framework and I'd rather not change the code of the function or the .lua it is from. So I want a function that repeats a number for me a certain amount of times so this is less repetitive. Something that could work like this and achieve what was done above
thisFunction(repeatNum(1,3),repeatNum(2,4),3,repeatNum(4,2),7,4,2)
is this possible in Lua? I'm even comfortable with something like this:
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
I think you're stuck with something along the lines of your second proposed solution, i.e.
thisFunction(repeatNum(1,3,2,4,3,1,4,2,7,1,4,1,2,1))
because if you use a function that returns multiple values in the middle of a list, it's adjusted so that it only returns one value. However, at the end of a list, the function does not have its return values adjusted.
You can code repeatNum as follows. It's not optimized and there's no error-checking. This works in Lua 5.1. If you're using 5.2, you'll need to make adjustments.
function repeatNum(...)
local results = {}
local n = #{...}
for i = 1,n,2 do
local val = select(i, ...)
local reps = select(i+1, ...)
for j = 1,reps do
table.insert(results, val)
end
end
return unpack(results)
end
I don't have 5.2 installed on this computer, but I believe the only change you need is to replace unpack with table.unpack.
I realise this question has been answered, but I wondered from a readability point of view if using tables to mark the repeats would be clearer, of course it's probably far less efficient.
function repeatnum(...)
local i = 0
local t = {...}
local tblO = {}
for j,v in ipairs(t) do
if type(v) == 'table' then
for k = 1,v[2] do
i = i + 1
tblO[i] = v[1]
end
else
i = i + 1
tblO[i] = v
end
end
return unpack(tblO)
end
print(repeatnum({1,3},{2,4},3,{4,2},7,4,2))
When programming in Ruby I quite often have assignments like the following
test = some_function if some_function
With that assignments I want to assign the output of a function, but if it returns nil I want to keep the content of the variable. I know there are conditional assignments, but neither ||= nor &&= can be used here. The shortest way I found to describe the statement above is
test = (some_function or test)
Is there a better / shorter way to do this?
I don't think there's anything better than the last snippet you showed but note that or is used for flow control, use || instead:
test = some_function || test
It's usually better to assign new values to new names, the resulting code is easier to understand and debug since variables/symbols have the same value throughout the scope:
some_different_and_descriptive_name_here = some_function || test
I'd just add parentheses
(a = b) unless b.nil?
(a = b) if b
being inferior because if b is false then a remains as before
Keep in mind that this evaluates b twice, so if b is a function with side-effects (such as changing variables outside of its scope or printing) it will do that twice; to avoid this you must use
temp = b; (a = temp) unless temp.nil?
(which can, of course, be split into)
temp = b
(a = temp) unless temp.nil?