how to populate a hash in lua?

Post Reply
gnome power
Posts: 5
Joined: Tue Mar 06, 2012 2:17 pm

how to populate a hash in lua?

Post by gnome power »

Hi everyone,

I am trying to populate a hash (or dictionary?) in Lua for Mudlet. I made up an example just to make an alias and try to get it to work, so I've got the following:

Code: Select all

magichash = {}

magichash["fish"]["water"]["plankton"]["scales"] = 1
magichash["cow"]["land"]["grass"]["fur"] = 2



	echo("test")

  for animal, terrain in pairs (magichash) do

		for food, skin in pairs (terrain) do

	echo(animal)
end
end 
I've also tried using magichash.cow.land.grass.fur = 2, for example.

It seems to run into problems when I try to use keys (eg., cow, land, grass) that I haven't explicitly entered into the dictionary when I first called it.

The exception is the final key. If I make a nested hash and define all of these keys, all the way down to the final key ("fur"), then it allows me to put in a new (not previously defined) key in the position of "fur" and still read it out using a pairs (magichash) for loop. For example, this example (which I altered from an example I found online) works:

Code: Select all

stores = {
  Acknor = {
    Wood = {
      sell = 68,
      stock = 0,
      buy = 8,
      },
    Silver = {
      sell = 118,
      stock = 0,
      buy = 14,
      },
    },
  Paavik = {
    Wood = {
      sell = 68,
      stock = 104,
      buy = 5,
      },
    Silver = {
      sell = 119,
      stock = 0,
      buy = 5,
      },
    },
  }


stores["Acknor"]["Wood"]["booya"] = 43  -- I entered this line with a new key, "booya"


  for store, inventory in pairs (stores) do
  for item, details in pairs (inventory) do
	--echo(store)
    if item == "Wood" and details.booya > 0 then
      echo(store..", "..details.booya)
    end -- if
   
  
  end -- for each item
end -- for each store
(I found that example online and then added in the booya key to test it)

However, when I try to add any higher level key that I did not put in the original hash's definition, for example by doing stores["Acknor"]["foo"]["booya"] = 43, then it breaks the script.

As you can probably tell, I'm really confused at this point. :) Ultimately my goal is to make

Code: Select all

hash = {}
and then define elements arbitrarily:

Code: Select all

hash.fish.bone.face = 3

or

hash["fish"]["bone"]["face"] = 3
And then read it out using for loops like shown above. How do I do this? Sorry for the confusion.

Thanks!

User avatar
tsuujin
Posts: 695
Joined: Fri Feb 26, 2010 12:59 am
Location: California
Contact:

Re: how to populate a hash in lua?

Post by tsuujin »

One of the few irritating quirks of Lua is that it's tables don't do a whole lot to manage themselves. In order to define a hash like you're looking for you need to explicitly define each one up the tree.

so
Code: [show] | [select all] lua
arr["this"]["is"]["a"]["long"]["hash"] = "isn't it?"
has to be defined as
Code: [show] | [select all] lua
arr["this"] = {}
arr["this"]["is"] = {}
arr["this"]["is"]["a"] = {}
et cetera.

At first it seems cumbersome, but after a while you don't really notice it anymore. You can even write quick little functions to take a string, tokenize it by word and create your hash listing automatically.

gnome power
Posts: 5
Joined: Tue Mar 06, 2012 2:17 pm

Re: how to populate a hash in lua?

Post by gnome power »

Ohhhhh, perfect.

Thanks!

gnome power
Posts: 5
Joined: Tue Mar 06, 2012 2:17 pm

Re: how to populate a hash in lua?

Post by gnome power »

Hi tsuujin or anyone else,

Thanks to your advice, I got about 95% of the way there. My issue now is I can't seem to access the element of the array. For example, suppose that I have an array that goes something like

battle_data[attacker][victim][type][info] = 32

That's just an example, in reality I have a script that's filling in specific strings for attacker, victim, etc.

Okay, so now I'm trying to use an alias to unpack everything in that hash. I get all the keys to the 32. I can't get the 32 somehow. But I know the 32 is populating, because when I get the number of items in the info array I get lots of matches. For example, the following code...

Code: Select all

  for attackers, damTargets in pairs (battle_data) do
		for victims, nouns in pairs (damTargets) do
			for nountypes, info in pairs (nouns) do
				for infotypes,values in pairs (info) do
	echo(tostring(attackers))
	echo(tostring(victims))
	echo(tostring(nountypes))
	echo(tostring(infotypes))
	--echo(tostring(values))
	echo(# infotypes.."\n")
end
end
end
end
generates the following output…
YourKeglumchop misses6
YourKeglumchop <cornsilk>h<white>18
YourKeglumchop hits4
YourKeglumpierce misses6
YourKeglumpierce <cornsilk>h<white>18
YourKeglumpierce hits4
YouKeglumevadedtotal_hits10
Keglumyouslash misses6
Keglumyouslash hits4
Keglumyouevadedmisses6
however, if I just try to echo(values) I get no echos. If I try to echo(tostring(values)) I get tables. If I try # values then it says 0. if I do echo(battle_data.attacker.victim.type.info) (where I fill in the actual string for each of those keys) then I get no echo. I've also tried the echo(battle_data["attacker"]["victim… etc equivalent, and get no echo.

I'm so confused. Maybe someone can help. I just want to recover the number for each type.info.

Thanks!

User avatar
tsuujin
Posts: 695
Joined: Fri Feb 26, 2010 12:59 am
Location: California
Contact:

Re: how to populate a hash in lua?

Post by tsuujin »

as long as the keys are populated, it should just be a simple issue of echoing it out.
Code: [show] | [select all] lua
arr["another"]["test"]["of"]["arrays"] = "This is the resulting echo"
echo(arr["another"]["test"]["of"]["arrays"])
If you're having problems with it, the first step is to simply check for existence with an if statement
Code: [show] | [select all] lua
if arr["another"]["test"]["of"]["arrays"] then
    echo("Yep.")
else
    echo("Nope.")
end

gnome power
Posts: 5
Joined: Tue Mar 06, 2012 2:17 pm

Re: how to populate a hash in lua?

Post by gnome power »

tsuujin wrote:as long as the keys are populated, it should just be a simple issue of echoing it out.
Code: [show] | [select all] lua
arr["another"]["test"]["of"]["arrays"] = "This is the resulting echo"
echo(arr["another"]["test"]["of"]["arrays"])
If you're having problems with it, the first step is to simply check for existence with an if statement
Code: [show] | [select all] lua
if arr["another"]["test"]["of"]["arrays"] then
    echo("Yep.")
else
    echo("Nope.")
end
Thanks, Tsuujin.

I did that, and it echos as "Yep."

When I try to do the following script:

Code: Select all

  for attackers, damTargets in pairs (battle_data) do
		for victims, nouns in pairs (damTargets) do
			for nountypes, info in pairs (nouns) do
				for infotypes,values in pairs (info) do
	echo(tostring(attackers))
	echo(tostring(victims))
	echo(tostring(nountypes))
	echo(tostring(infotypes))
	echo(tostring(values))
	--echo(# infotypes)
	echo(tostring(battle_data[tostring(attackers)][tostring(victims)][tostring(nountypes)][tostring(infotypes)]).."\n")

end
end
end
end 
the output is the following:


Youra lizardchop missestable: 0x7fd64e0table: 0x7fd64e0
Youra lizardchop hitstable: 0x7f9ab30table: 0x7f9ab30

So it's generating a table for

battle_data[tostring(attackers)][tostring(victims)][tostring(nountypes)][tostring(infotypes)]

that is equal to what it reports if I do echo(tostring(values))

but when I try to add another "for" loop to unpack the values table, then it breaks the script when I try to echo the resulting keys. I use the following code:

Code: Select all

  for attackers, damTargets in pairs (battle_data) do
		for victims, nouns in pairs (damTargets) do
			for nountypes, info in pairs (nouns) do
				for infotypes,values in pairs (info) do

					for k, v in pairs (values) do
	echo(tostring(attackers))
	echo(tostring(victims))
	echo(tostring(nountypes))
	echo(tostring(infotypes))
	echo(tostring(values))
	--echo(# infotypes)
	echo(tostring(battle_data[tostring(attackers)][tostring(victims)][tostring(nountypes)][tostring(infotypes)]).."\n")
	echo(tostring(v))
end
end
end
end
end
I just added the for loop and the echo(tostring(v)) and there is no output.

I also replace v with k, and there is no output. I delete this echo line altogether, so only the for loop is left, and the script doesn't work. So the for loop must be breaking it.

The way I am populating the battle_data dictionary is with the following script (after some code to generate all the keys, which I know are working fine because I can echo them using the above code):

Code: Select all

if battle_data == nil then
battle_data = battle_data or {}
battle_data[attacker]=battle_data[attacker] or {}
battle_data[attacker][damTarget]=battle_data[attacker][damTarget] or {}
battle_data[attacker][damTarget][noun]=battle_data[attacker][damTarget][noun] or {}
battle_data[attacker][damTarget][noun]["hits"]=battle_data[attacker][damTarget][noun]["hits"] or {}
battle_data[attacker][damTarget][noun]["misses"]=battle_data[attacker][damTarget][noun]["misses"] or {}
battle_data[attacker][damTarget][noun]["total_hits"]=battle_data[attacker][damTarget][noun]["total_hits"] or {}
battle_data[attacker][damTarget][noun]["dam"] = battle_data[attacker][damTarget][noun]["dam"] or {}

battle_data[attacker]["you"] = battle_data[attacker]["you"] or {}
battle_data[attacker]["you"]["evaded"] = battle_data[attacker]["you"]["evaded"] or {}
battle_data[attacker]["you"]["evaded"]["misses"] = battle_data[attacker]["you"]["evaded"]["misses"] or {}

battle_data["You"] = battle_data["You"] or {}
battle_data["You"][damTarget] = battle_data["You"][damTarget] or {}
battle_data["You"][damTarget]["evaded"] = battle_data["You"][damTarget]["evaded"] or {}
battle_data["You"][damTarget]["evaded"]["total_hits"] = battle_data["You"][damTarget]["evaded"]["total_hits"] or {}

battle_data[attacker][damTarget][noun]["<gold>s<white>"] = battle_data[attacker][damTarget][noun]["<gold>s<white>"] or {}

battle_data[attacker][damTarget][noun]["<red>f<white>"] = battle_data[attacker][damTarget][noun]["<red>f<white>"] or {}

battle_data[attacker][damTarget][noun]["<cornsilk>h<white>"] = battle_data[attacker][damTarget][noun]["<cornsilk>h<white>"] or {}

battle_data[attacker][damTarget][noun]["<deep_pink>m<white>"] = battle_data[attacker][damTarget][noun]["<deep_pink>m<white>"] or {}

battle_data[attacker][damTarget][noun]["<dark_orchid>S<white>"] = battle_data[attacker][damTarget][noun]["<dark_orchid>S<white>"] or {}

battle_data[attacker][damTarget][noun]["<powder_blue>f<white>"] = battle_data[attacker][damTarget][noun]["<powder_blue>f<white>"] or {}

end

if damAssign > 0 then
	battle_data[attacker][damTarget][noun]["hits"]= (battle_data[attacker][damTarget][noun]["hits"] or 0) +1
	else
	battle_data[attacker][damTarget][noun]["misses"] = (battle_data[attacker][damTarget][noun]["misses"] or 0) +1
	end --if


battle_data[attacker][damTarget][noun]["total_hits"] = (battle_data[attacker][damTarget][noun]["total_hits"] or 0) + 1
    
battle_data[attacker][damTarget][noun]["dam"] = (battle_data[attacker][damTarget][noun]["dam"] or 0) + damAssign

I have some more code to populate the other categories (like the [powder_blue]f and stuff) but I'm just showing an example here because it's more of the same for that but with different trigger conditions.

Am I doing something wrong in assigning my values?

For some reason I can't seem to echo the numbers they equal.

Thanks!

edit: I should note that I also tried "tonumber" instead of "tostring" for

Code: Select all

echo(tonumber(values))
echo(tonumber(battle_data[tostring(attackers)][tostring(victims)][tostring(nountypes)][tostring(infotypes)]).."\n")
But it breaks the script at that line too (and echos everything prior to it)

gnome power
Posts: 5
Joined: Tue Mar 06, 2012 2:17 pm

Re: how to populate a hash in lua?

Post by gnome power »

Thanks, I figured it out.

Turns out I had to put

if not battle_data[etc][etc] then
battle_data[etc][etc] = {}
end

in front of every script for each key…

Thanks for all your help

User avatar
tsuujin
Posts: 695
Joined: Fri Feb 26, 2010 12:59 am
Location: California
Contact:

Re: how to populate a hash in lua?

Post by tsuujin »

Yeah. All of my functions that assign multi-dimensional array variables run a check exactly like that beforehand because it's just easier than worrying about getting errors.

For future reference, you can always check to see what you're assigning by using the type() function.

Also, why do you have all of those tostring calls? Lua is pretty loose about typing, I can't think of a time I've actually needed to cast like that.

User avatar
chris
Posts: 493
Joined: Fri Jun 17, 2011 5:39 am

Re: how to populate a hash in lua?

Post by chris »

Here's a nifty tool for these type of tables:
http://lua-users.org/wiki/AutomagicTables

Post Reply