How to work with tables in Corona SDK - lua

I have a sort of general question but i think that if I tried to be too specific I would only make it very confusing. So basically what I want to know is this:
When you create a table in Corona/Lua you can put pretty much an unlimited number of things in it correct?
So say i create a table called
rectangles = {};
and then i put a bunch of instances of rectangles in it. If i wanted to change a property of ALL the rectangles at once, how could I do it?
I understand how it would work with a set number of items in the table, like:
for i = 1, 10 do
rectangles[i] = display.newImage("rectangle.png");
then to change all of the images x positions for instance you would simply say
rectangles[i].x = 20;
but how would you change a property of all items in the array without knowing how many there are, as in you didnt give an upper bound, and cant because the table is always growing?

For arrays that have only one kind of elements you can use #rectangles for element count.
for i = 1, #rectangles do
rectangles[i] = display.newImage("rectangle.png");
end
Regarding the youtube example,
if you add element into rectangles like this:
rectangles[b]=b;
what it actually does is
rectangles["083DF6B0"]=b"
you see when a display object b is used as a key it is converted into a hex string.
in addition, you would need to use pairs to go over each element as they are
keys (e.g. array.length,array.width,array.weight..) rather than index (e.g. array[2],array[3]..)
for key,value in pairs(rectangles) do
print(key); --prints 083DF6B0
print(value); --prints 20
rectangles[key]=30;
end

It depends on how you're storing items in the table. If you're storing by index (as in your example), you can use ipairs to iterate over indexes and values:
for index,value in ipairs(rectangles) do
value.x = 20
--or
rectangles[index].x = 20
end
If you're storing by key (as in the youtube video you mention in a comment), iterate using pairs:
for key,value in pairs(rectangles) do
value.x = 20
--or
rectangles[key].x = 20
end
Just don't store items using both index and keys, unless you know what to expect.

Related

Lua 5.0 - iterations over tables ignore duplicate keys even though values are different

Reading the injected comments in the Code Snippet should give enough context.
--| Table |--
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
--| Code Snippet |--
--| gets QuestName then does below |--
if QuestName then
-- (K = QuestName) and (V = the 3 entries below it in the table)
for k,v in pairs(QuestData) do
-- Checks to make sure the external function that obtained the QuestName matches what is in the table before cont
if strlower(k) == strlower(QuestName) then
local index = 0
-- Iterates over the first two pairs - Quest Descrip key and values
for kk,vv in pairs(v) do
index = index + 1
end
-- Iterates over the second two pairs of values
if index == 1 then
for kk,vv in pairs(v) do
-- Sends the 10 digit hash number to the function
Quest:Function(vv[2])
end
end
end
end
end
The issue I'm running into is that Lua will only pick up one of the numbers and ignore the rest. I need all the possible hash numbers regardless of duplicates. The QuestData table ("database") has well over 10,000 entries. I'm not going to go through all of them and remove the duplicates. Besides, the duplicates are there because the same quest can be picked up in more than one location in the game. It's not a duplicate quest but it has a different hash number.
Key is always unique. It is the point of the key, that the key is pointing to unique value and you can't have more keys with same name to point different values. It is by definition by Lua tables.
It is like if you would want to have two variables with same name and different content. It does not make sense ...
The table type implements associative arrays. [...]
Like global variables, table fields evaluate to nil if they are not initialized. Also like global variables, you can assign nil to a table field to delete it. That is not a coincidence: Lua stores global variables in ordinary tables.
Quote from Lua Tables
Hashing in Lua
Based on comments, I update the answer to give some idea about hashing.
You are using hashing usually in low-level languages like C. In Lua, the associative arrays are already hashed somehow in the background, so it will be overkill (especially using SHA or so).
Instead of linked lists commonly used in C, you should just construct more levels of tables to handle collisions (there is nothing "better" in Lua).
And if you want to have it fancy set up some metatables to make it somehow transparent. But from your question, it is really not clear how your data look like and what you really want.
Basically you don't need more than this:
QuestData = {
["QuestName"]={
["Quest Descrip"]={
{8,1686192712},
{32,1686193248},
{0,2965579272},
},
},
}
As Jakuje already mentioned table keys are unique.
But you can store both as a table member like:
QuestData = {
-- "QuestName" must be unique! Of course you can put it into a table member as well
["QuestName"]={
{hash = "Quest Descrip", values = {8,1686192712} },
{hash = "Quest Descrip", values = {32,1686193248} },
{hash = "Quest Descrip", values = {0,2965579272} }
}
}
I'm sure you can organize this in a better way. It looks like a rather confusing concept to me.
You've said you can't "rewrite the database", but the problem is the QuestData table doesn't hold what you think it holds.
Here's your table:
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
But, this is actually like writing...
QuestData["Quest Descrip"] = {8,1686192712}
QuestData["Quest Descrip"] = {32,1686193248}
QuestData["Quest Descrip"] = {0,2965579272}
So the second (and then, third) values overwrite the first. The problem is not that you can't access the table, but that the table doesn't contain the values any more.
You need to find a different way of representing your data.

Potential problems with storing the second table of two dimensional arrays in the index

In the past I found myself using a table as index and value of
a table when the order was irrelevant.
Since every table returns a unique value they are save to use as
index and with that I already got all the information I want to
use later on in the program. Now I did not see any similar lua code
jet and didn't use it in a non test-program. So I'm worrying that I
might get some unforeseen/unexpected problems when using this method.
example:
a = {1,2,3,4,5} --some testing values
b = {2,nil,4,nil,1}
c = {3,nil,nil,nil,2}
d = {4,nil,1,nil,3}
e = {5,1,2,3,4}
tab = {a,b,c,d,e}
t = {}
for i, v in pairs(tab) do
t[v] = 0
end
for iv in pairs(t) do --is almost every time outputting it in a different order
print(iv[1],iv[2],iv[3],iv[4],iv[5]) --could be a list of data where you have to go through all of it anyway
end
io.read()
Now I can store some additional information in t[v] but if I don't have
any is there maybe some lua-type that is smaller?
Edit:
Does this go well with the use of weak-tables?
Note:
Standard 2d table: table[key1] = table
table[key1][key2] <-- contains stuff
this version: table[table] = anything but nil <-- not accessible over table[key1][key2]
key1[key2] <-- contains stuff
It's fine to use a table as a key in another table.
However, note that different tables will be different keys, even of the tables have the same contents.

How to extract records at position x from an array?

In Rails (or Ruby), is it possible to target and manipulate items at a certain position within an array.
For example, say I have defined an array that cannot exceed 10 records.
#array = Model.where(:my_query = something).order(:my_order).first(10)
Now I want to do something with the first 5 records, and something else with the last five. I could use
#array.first(5)
#array.last(5)
but this falls apart if :my_query returns less than 10 records—i.e. there will be overlap.
#array.at(1)
returns a single position, but what if I need a range of positions. I'm looking for something like
#array.position(1..5)
#array.position(6..10)
Does something like this exist? I'm not sure what search terms I should be Googling?
You want something like this:
first = #array[0..4]
last = #array[5..9]
That will return the first five and the last five elements from the array in two separate variables. If you do it this way and you will not get any overlap.

How to get the program and feature in the lua table

from the below
Control Panel\Programs\Programs and Features
Need the List view in the Lua table
Suppose the Name of the Program installed , its version and size etc.
Issue is Lua seems to doesn't takes two argument like two dimension array
Using Lua table you can store List of string
But how to store a two dimension array ?
table = {}
for i = 1, 10 do
table[i] = {}
for j = 1, 10
table[i][j] = i+j
end
end
A multidimensional array in Lua is simply multiple tables in another :), one for each row/col.
Oh and another option is faking a multidimensional array through some simple arithmatic, something like: table[x+rowlen*y]

How do I collect and combine multiple arrays for calculation?

I am collecting the values for a specific column from a named_scope as follows:
a = survey_job.survey_responses.collect(&:base_pay)
This gives me a numeric array for example (1,2,3,4,5). I can then pass this array into various functions I have created to retrieve the mean, median, standard deviation of the number set. This all works fine however I now need to start combining multiple columns of data to carry out the same types of calculation.
I need to collect the details of perhaps three fields as follows:
survey_job.survey_responses.collect(&:base_pay)
survey_job.survey_responses.collect(&:bonus_pay)
survey_job.survey_responses.collect(&:overtime_pay)
This will give me 3 arrays. I then need to combine these into a single array by adding each of the matching values together - i.e. add the first result from each array, the second result from each array and so on so I have an array of the totals.
How do I create a method which will collect all of this data together and how do I call it from the view template?
Really appreciate any help on this one...
Thanks
Simon
s = survey_job.survey_responses
pay = s.collect(&:base_pay).zip(s.collect(&:bonus_pay), s.collect(&:overtime_pay))
pay.map{|i| i.compact.inject(&:+) }
Do that, but with meaningful variable names and I think it will work.
Define a normal method in app/helpers/_helper.rb and it will work in the view
Edit: now it works if they contain nil or are of different sizes (as long as the longest array is the one on which zip is called.
Here's a method that will combine an arbitrary number of arrays by taking the sum at each index. It'll allow each array to be of different length, too.
def combine(*arrays)
# Get the length of the largest array, that'll be the number of iterations needed
maxlen = arrays.map(&:length).max
out = []
maxlen.times do |i|
# Push the sum of all array elements at a given index to the result array
out.push( arrays.map{|a| a[i]}.inject(0) { |memo, value| memo += value.to_i } )
end
out
end
Then, in the controller, you could do
base_pay = survey_job.survey_responses.collect(&:base_pay)
bonus_pay = survey_job.survey_responses.collect(&:bonus_pay)
overtime_pay = survey_job.survey_responses.collect(&:overtime_pay)
#total_pay = combine(base_pay, bonus_pay, overtime_pay)
And then refer to #total_pay as needed in your view.

Resources