Mixing "Arrays" with "Hashes" in Corona/Lua

This is not quite a n00b question, but it’s one I should know but I don’t and before I program myself into a hole that I will have trouble programming out of, can I do this:

I have a list of IAP products in a table (array) that I have in a module

items.lua  
--  
local items = {}  
  
items[1] = {}  
items[1].name = "Fred"  
items[1].price = "$0.99"  
items[1].purchased = false  
items[2] = {}  
items[2].name = "Barney"  
items[2].price = "$1.99"  
items[2].purchased = false  
  
return items  

I can do an:

local items = require("items")  

and I have a lovely table that I can use. I save that table out to system.DocumentsDirectory after the client buys something by setting the purchased member to true and using my handy-dandy table writer to write it out.

I want to keep this a numerically indexed table so my client can add new items later by just updating the one module. But I also need them to be able to change the values, like the price, description and other data that I’m tracking.

When a user downloads an update, I need to see if my in memory version is newer than the one on the file system. I can’t blindly replace it because the saved version has their local information (purchased, and other flags that get set).

What I want to do is have my module above return the table but also return a version number. I can then compare the version numbers of my saved version vs my in-memory version and if I have a new version, then I can preserve the customer’s information and update the master table.

I tried to have the module return two items:

return items, version -- where version is an incrementing number  
  
-- in main.lua:  
  
items, version = require("items")  

Well that worked as well as a wet blanket. So my question (yea I’m finally getting around to it), is this. Can I do this:

local items = {}  
  
items[1] = {}  
items[1].name = "Fred"  
items[1].price = "$0.99"  
items[1].purchased = false  
items[2] = {}  
items[2].name = "Barney"  
items[2].price = "$1.99"  
items[2].purchased = false  
items.version = 5  

I know i can do that, but will my ability to do #items still return 2 in this example. I think Lua really doesn’t like mixing metaphors for it’s tables. Either you should do associative arrays/hashes or you do numeric arrays. If my ability to get an accurate count of the numeric array with #items will still work, then I’ll be okay.

Thoughts?
Thanks
Rob [import]uid: 19626 topic_id: 33271 reply_id: 333271[/import]

You can.

The # operator returns the numerical index before the first nil index when going 1, 2, 3, 4, etc…

So you can even store low-value indices, and then high-value numerical ids in the same table, and # will return the highest low-value index, or simply the highest value before the first nil.

If merging with previous versions is an issue due to the Purchased flag, can you not put it in a different table?

local mtx = {}  
local items = {}  
   
items[1] = {}  
items[1].name = "Fred"  
items[1].price = "$0.99"  
items[2] = {}  
items[2].name = "Barney"  
items[2].price = "$1.99"  
items.version = 5  
mtx.items = items  
mtx.purchased = { 2 = true, "Barney"} --Storing both mean you can look up purchased items by name or index (or you could use an id of some kind  

Then you can overwrite items as a whole without risking any modifications to mtx.purchased. [import]uid: 134101 topic_id: 33271 reply_id: 132202[/import]

I thought about the 2nd route, but I’ve got quite a few places I’m expecting that table to be top level. Of course I could always assign a pointer to where I need it.

Good advice.

[import]uid: 19626 topic_id: 33271 reply_id: 132204[/import]

Yes, you can. Be aware that you’re “mixing metaphors” in your code and I think this should work fine. There is nothing wrong with having a version number attached to the list because you can use # to find the number of numerically indexed items and even [lua]for k,v pairs(t) do[/lua] to iterate the full list of numerically indexed and named items. [import]uid: 8271 topic_id: 33271 reply_id: 132226[/import]

You can.

The # operator returns the numerical index before the first nil index when going 1, 2, 3, 4, etc…

So you can even store low-value indices, and then high-value numerical ids in the same table, and # will return the highest low-value index, or simply the highest value before the first nil.

If merging with previous versions is an issue due to the Purchased flag, can you not put it in a different table?

local mtx = {}  
local items = {}  
   
items[1] = {}  
items[1].name = "Fred"  
items[1].price = "$0.99"  
items[2] = {}  
items[2].name = "Barney"  
items[2].price = "$1.99"  
items.version = 5  
mtx.items = items  
mtx.purchased = { 2 = true, "Barney"} --Storing both mean you can look up purchased items by name or index (or you could use an id of some kind  

Then you can overwrite items as a whole without risking any modifications to mtx.purchased. [import]uid: 134101 topic_id: 33271 reply_id: 132202[/import]

I thought about the 2nd route, but I’ve got quite a few places I’m expecting that table to be top level. Of course I could always assign a pointer to where I need it.

Good advice.

[import]uid: 19626 topic_id: 33271 reply_id: 132204[/import]

Yes, you can. Be aware that you’re “mixing metaphors” in your code and I think this should work fine. There is nothing wrong with having a version number attached to the list because you can use # to find the number of numerically indexed items and even [lua]for k,v pairs(t) do[/lua] to iterate the full list of numerically indexed and named items. [import]uid: 8271 topic_id: 33271 reply_id: 132226[/import]