Constructing a table using values from another table.

Posted by Bobble on Thu 27 Nov 2008 03:12 AM — 7 posts, 28,490 views.

Canada #0
Greets everyone,

I'm encountering a problem that I'm sure has a simple solutions, but I'm just missing it.

I have a table used for another purpose, but would like to use the information in that table to construct a different table.

This original table looks like this:


characters = {
     {name = "jim"     ,race = "dwarf"     ,class = "priest"}
     {name = "john"    ,race = "dwarf"     ,class = "warrior"}
     {name = "ben"     ,race = "human"     ,class = "priest}
     {name = "lynn"    ,race = "elf"       ,class = "warrior"}
     {name = "terry"   ,race = "elf"       ,class = "warrior"}
}


What I want to do is make a function that uses this table to create a new table where the keys are the races and the values are the names of people that belong to that race.

Thus one of the key value pairings in this new table would be:

dwarf = "jim, john"
etc.

I tried doing this:


for _, v in ipairs(characters) do
	race_index [v.race] = v.name
end


Of course, the problem with this is that instead of adding the name to the value of the race key, it's overwriting the value.

Any ideas on how to get each name added to the respective race key?

Please let me know if I need to clarify anything or further information is required.
Amended on Thu 27 Nov 2008 03:13 AM by Bobble
USA #1
for _, v in ipairs(characters) do
	race_index [v.race] = race_index [v.race] or {}
        race_index [v.race][#race_index [v.race] + 1] = v.name
end


Would be the easiest way. It essentially makes:

race_index = { dwarf = {"jim" , "john" } ,
               human = { "ben" } ,
               elf   = { "lynn", "terry" }
             }

# is the length operator. For tables it returns the highest contiguous index in the table. (i.e. in a table that's t = {1,2,3, [5] = 5, foo = "bar", sample = "contrived"} - #t is 3, the highest sequential index; not 5 the highest ordinal, or 6 the number of elements in the table) so "t[#t + 1]" is how you append to the end of a table in Lua.


If having nested tables isn't to your liking, after populating the tables you can use

Race_Index = {}
for r,t in pairs(race_index) do
 Race_Index[r] = table.concat(t , ", ")
end

to get the dwarf = "jim, john" formatting.

Netherlands #2
Easiest would be to do something like:


for _, v in ipairs(characters) do
  -- Make sure table entry exists.
  race_index [v.race] = race_index [v.race] or {}
  table.insert(race_index [v.race], v.name)
end

-- To display in the format you gave...

-- Taken from: http://lua-users.org/wiki/SplitJoin
-- Concat the contents of the parameter list,
-- separated by the string delimiter (just like in perl)
-- example: strjoin(", ", {"Anna", "Bob", "Charlie", "Dolores"})
function strjoin(delimiter, list)
  local len = getn(list)
  if len == 0 then 
    return "" 
  end
  local string = list[1]
  for i = 2, len do 
    string = string .. delimiter .. list[i] 
  end
  return string
end

-- here it comes:

Note(strjoin(", ", race_index [v.race]))



It might seem a bit difficult or long, but this way you get to use the values for other purposes than displaying too (and add/remove or whatever). Your original approach didn't work because the key is unique (hence it being called a key).

A shorter variety could also be made in one line: Just append (", "..v.name) every time, and do a string.sub() at the end which removes the first few characters. But again, that is only a useful approach if you do not need the names or information for other purposes.


Edited: Fixed. Thanks Nick, it was the last thing I wrote before hitting the pillow. :)
Amended on Thu 27 Nov 2008 01:01 PM by Worstje
Australia Forum Administrator #3
You need to "escape forum codes" Worstje - your [i] has turned the second half of your post into italics.
Canada #4
Thanks to both of you! I got exactly what I needed.
USA #5
Hey Worstje, what's the difference between the StrJoin function you wrote and the table.concat() function?

Seems like they accomplish the same thing.
Netherlands #6
I didn't write it. I took it from the wiki-page I referenced.

And why I don't use table.concat... well, it's a good question. I always think of said operation as a join(), and unless I read over it said wiki page doesn't reference table.concat() either. And I just searched the document.. it's all the way on the bottom, inbetween version specific stuff near the footer. Gah! :/

Besides that, I end up reinventing the wheel in Lua often enough that I don't question those pages anymore. If I see a page dedicated to the exact topic I need, and it doesn't reference a builtin function, I've become used to just accepting Lua doesn't have a builtin for it and that I need to use some snippet for it.

On that sidenote.. this function is still a nice template for when you need to merge members of tables, which cannot be done with table.concat. :)