Message
| Tables as vectors
As noted above, normal tables do not guarantee any particular order for returning their entries, using a linear scan (table.foreach).
However often we want to keep our data in some kind of sequence. Lua provides for that by the concept of using numeric keys for tables, and assuming that you can scan through a table by starting at key 1, and progressing through it until you reach the 'size' of the table.
Let's look at a table with a combination of numeric and string keys:
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
hp = 22,
mana = 44,
skill = 80
}
table.foreach (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 jumped
mana 44
hp 22
skill 80
As it turns out, the numeric keys have been displayed in sequence, but this is not necessarily going to be the case. Now let's print using 'foreachi' which simply iterates over the numeric keys:
table.foreachi (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 jumped
Let's add item 7 manually and see what happens:
t [7] = "test"
table.foreachi (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 jumped
It still thinks there are only 5 items, because of the gap between 5 and 7. Let's put item 6 in ...
t [6] = "missing link"
table.foreachi (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 jumped
6 missing link
7 test
Now we see items 1 to 7. It is pretty clear how Lua is working internally. To go through a table sequentially it simply looks up key 1, then key 2, and so on, until it finds a gap, then it stops.
(Caveat - actually it sequences from 1 to the 'table size' which is something you can control. The default unless you start mucking around is the highest numeric key in sequence).
The other way we can go through the numeric items is to use 'for ... ipairs' like this:
for k, v in ipairs (t) do
print (k, v)
end -- for
Output
1 the
2 quick
3 brown
4 fox
5 jumped
6 missing link
7 test
In this case the 'ipairs' iterator only looks for numeric entries, starting at 1, rather than all table entries, which is what 'pairs' returns.
Inserting into a vector
A simple way of adding a numeric item to a table is by using table.insert, like this:
table.insert (t, "a new entry")
table.foreachi (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 jumped
6 missing link
7 test
8 a new entry
This function works out where the table ends, and appends a new entry to the end. You can also insert by specifying a position:
table.insert (t, 5, "trouble at mill")
table.foreachi (t, print)
Output
1 the
2 quick
3 brown
4 fox
5 trouble at mill
6 jumped
7 missing link
8 test
9 a new entry
This has made entry 5 into the new entry, and pushed all the others down by 1.
Removing items from a vector
The simple case lets you remove the last entry:
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
}
table.remove (t)
tprint (t)
Output
1="the"
2="quick"
3="brown"
4="fox"
You can specify which entry to remove:
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
}
table.remove (t, 3)
tprint (t)
Output
1="the"
2="quick"
3="fox"
4="jumped"
In this case it had to resequence each item past the deleted one, so each entry is still in sequence.
Sorting a table
If you sort a table, it resequences the keys, based on the comparison operation you give it. The default is to compare the values for "less than".
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
}
table.sort (t)
tprint (t)
Output
1="brown"
2="fox"
3="jumped"
4="quick"
5="the"
Only the "vector" part of the table is sorted, the rest (if any) is left alone:
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
hp = 22,
mana = 44,
skill = 80
}
table.sort (t)
tprint (t)
Output
1="brown"
2="fox"
3="jumped"
4="quick"
5="the"
"mana"=44
"hp"=22
"skill"=80
Specifying a sort sequence
In the case of simple values the default "less than" comparison may be fine, however some cases need an explicit comparison:
t = {
{ str = 22, dex = 23, wis = 18 },
{ str = 20, dex = 20, wis = 20 },
{ str = 18, dex = 24, wis = 25 },
}
table.sort (t) --> error: attempt to compare two table values
So, we supply a comparison function, and inside that choose which field to compare with. I will use the "str" field of the subtable, to sort them into "str" order ...
t = {
{ str = 22, dex = 23, wis = 18 },
{ str = 20, dex = 20, wis = 20 },
{ str = 18, dex = 24, wis = 25 },
}
table.sort (t,
function (v1, v2)
return v1.str < v2.str
end -- function
)
tprint (t)
Output
1:
"str"=18
"dex"=24
"wis"=25
2:
"str"=20
"dex"=20
"wis"=20
3:
"str"=22
"dex"=23
"wis"=18
We can see here that the table is now sorted into "str" order of the subtable entries.
Sorting the key
But how would we sort an alphabetic key, you might ask? Take for example this table:
t = {
dwarf = { str = 22, dex = 23, wis = 18 },
human = { str = 20, dex = 20, wis = 20 },
elf = { str = 18, dex = 24, wis = 25 },
}
How can we get that into alphabetic order by key? The trick is to use a second table, that refers to elements in the first one.
Here is one approach:
t = {
dwarf = { str = 22, dex = 23, wis = 18 },
human = { str = 20, dex = 20, wis = 20 },
elf = { str = 18, dex = 24, wis = 25 },
}
t2 = {}
table.foreach (t, function (k) table.insert (t2, k) end )
table.sort (t2)
tprint (t2)
Output
1="dwarf"
2="elf"
3="human"
Now the t2 table has the names in alphabetic order, so we can just pull them out in sequence (with 'table.foreachi', or 'for ... ipairs') and use the value (eg. dwarf) to index into the main table.
t = {
dwarf = { str = 22, dex = 23, wis = 18 },
human = { str = 20, dex = 20, wis = 20 },
elf = { str = 18, dex = 24, wis = 25 },
}
t2 = {}
table.foreach (t, function (k) table.insert (t2, k) end )
for k, v in ipairs (t2) do
print ""
print ("key = ", v)
table.foreach (t [v], print)
end -- for
Output
key = dwarf
str 22
dex 23
wis 18
key = elf
str 18
dex 24
wis 25
key = human
str 20
dex 20
wis 20
Converting a table into a string
For simple tables, table.concat can convert its values back into a string, like this:
t =
{
"the",
"quick",
"brown",
"fox",
"jumped",
}
print (table.concat (t, ","))
Output
the,quick,brown,fox,jumped
You can also specify the range of the table to operate over. However this simple technique will not work in every case (for example, if the values had commas in them).
A more sophisticated version is the serialize function which is supplied in the exampscript.lua file which ships with MUSHclient. This handles nested tables and other considerations.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|