How to sort this lua table? - sorting

I have next structure
self.modules = {
["Announcements"] = {
priority = 0,
-- Tons of other attributes
},
["Healthbar"] = {
priority = 40,
-- Tons of other attributes
},
["Powerbar"] = {
priority = 35,
-- Tons of other attributes
},
}
I need to sort this table by priorty DESC, other values does not matter.
E.g. Healthbar first, then Powerbar, and then going all others.
// edit.
Keys must be preserved.
// edit #2
Found a solution, thanks you all.
local function pairsByPriority(t)
local registry = {}
for k, v in pairs(t) do
tinsert(registry, {k, v.priority})
end
tsort(registry, function(a, b) return a[2] > b[2] end)
local i = 0
local iter = function()
i = i + 1
if (registry[i] ~= nil) then
return registry[i][1], t[registry[i][1]]
end
return nil
end
return iter
end

You can't sort a records table because entries are ordered internally by Lua and you can't change the order.
An alternative is to create an array where each entry is a table containing two fields (name and priority) and sort that table instead something like this:
self.modulesArray = {}
for k,v in pairs(self.modules) do
v.name = k --Store the key in an entry called "name"
table.insert(self.modulesArray, v)
end
table.sort(self.modulesArray, function(a,b) return a.priority > b.priority end)
for k,v in ipairs(self.modulesArray) do
print (k,v.name)
end
Output:
1 Healthbar 40
2 Powerbar 35
3 Announcements 0

Related

Table keys not sorting correctly

I have a table that looks like this
{
["slot1"] = {}
["slot2"] = {}
["slot3"] = {}
["slot4"] = {}
["slot5"] = {}
["slot6"] = {}
}
When I do a for k, v in pairs loop I want the keys to go from slot1- the last slot. At the moment when I do a loop the order is inconsistent, slot 5 comes first etc. What is the best way to do this?
also I did not design this table, and I cannot change how the keys look
You can write a simple custom iterator:
local tbl = {
["slot1"] = {},
["slot2"] = {},
["slot3"] = {},
["slot4"] = {},
["slot5"] = {},
["slot6"] = {}
}
function slots(tbl)
local i = 0
return function()
i = i + 1
if tbl["slot" .. i] ~= nil then
return i, tbl["slot" .. i]
end
end
end
for i, element in slots(tbl) do
print(i, element)
end
Output:
1 table: 0xd575f0
2 table: 0xd57720
3 table: 0xd57760
4 table: 0xd5aa40
5 table: 0xd5aa80
6 table: 0xd5aac0
Create a new table:
slot = {}
for k,v in pairs(original_table) do
local i=tonumber(k:match("%d+$"))
slot[i]=v
end
Lua table orders are undeterministic. see here what makes lua tables key order be undeterministic
For your table you can try this
local t = {
["slot1"] = {},
["slot2"] = {},
["slot3"] = {},
["slot4"] = {},
["slot5"] = {},
["slot6"] = {}
}
local slotNumber = 1
while(t['slot' .. slotNumber]) do
slot = t['slot' .. slotNumber]
-- do stuff with slot
slotNumber = slotNumber + 1
end
This method does not handle if the table skips a slot number.

parallel iteration in lua

I would like to for-loop through multiple tables in parallel in Lua. I could just do:
for i in range(#table1)
pprint(table1[i])
pprint(table2[i])
end
But I'd rather something like python's zip:
for elem1, elem2 in zip(table1, table2):
pprint(elem1)
pprint(elem2)
end
Is there such a thing in standard Lua (or at least in whatever comes packaged with torch?).
If you want something in Lua that's similar to some Python function, you should look at Penlight first. For this specific case there is the seq.zip function. It seems that Penlight is installed together with Torch, but you can also get it via LuaRocks (which again is bundled with at least one Torch distribution).
Anyway, the seq.zip function in Penlight only supports zipping two sequences. Here is a version that should behave more like Python's zip, i.e. allowing more (or less) than two sequences:
local zip
do
local unpack = table.unpack or unpack
local function zip_select( i, var1, ... )
if var1 then
return var1, select( i, var1, ... )
end
end
function zip( ... )
local iterators = { n=select( '#', ... ), ... }
for i = 1, iterators.n do
assert( type( iterators[i] ) == "table",
"you have to wrap the iterators in a table" )
if type( iterators[i][1] ) ~= "number" then
table.insert( iterators[i], 1, -1 )
end
end
return function()
local results = {}
for i = 1, iterators.n do
local it = iterators[i]
it[4], results[i] = zip_select( it[1], it[2]( it[3], it[4] ) )
if it[4] == nil then return nil end
end
return unpack( results, 1, iterators.n )
end
end
end
-- example code (assumes that this file is called "zip.lua"):
local t1 = { 2, 4, 6, 8, 10, 12, 14 }
local t2 = { "a", "b", "c", "d", "e", "f" }
for a, b, c in zip( {ipairs( t1 )}, {ipairs( t2 )}, {io.lines"zip.lua"} ) do
print( a, b, c )
end
--------------------------------------------------------------------------------
-- Python-like zip() iterator
--------------------------------------------------------------------------------
function zip(...)
local arrays, ans = {...}, {}
local index = 0
return
function()
index = index + 1
for i,t in ipairs(arrays) do
if type(t) == 'function' then ans[i] = t() else ans[i] = t[index] end
if ans[i] == nil then return end
end
return unpack(ans)
end
end
--------------------------------------------------------------------------------
-- Example use:
--------------------------------------------------------------------------------
a = {'a','b','c','d'}
b = {3,2,1}
c = {7,8,9,10,11}
for a,b,c,line in zip(a,b,c,io.lines(arg[0])) do
print(a,b,c,line)
end
print '\n--- Done! ---'
Made a version with variable number of lists based on the other responses and added coroutines, it's not the fastest but I think it's very readable. I'm gonna use it but maybe someone else also finds it usefull.
Also this was made for use with neovim's LuaJit.
local zipgen = function(args)
-- find smallest iterator's size
local min = #args[1]
for i = 2, #args, 1 do
min = #args[i] < min and #args[i] or min
end
-- create list with 'i'th element from all iterators
for i=1, min do
local ans = {}
for j=1, #args do
-- get 'j'th iterator's 'i'th element
ans[j] = args[j][i]
end
-- return list of 'i'th elements
coroutine.yield(unpack(ans))
end
end
-- python like zip iterator
zip = function(...)
local args = {...}
-- return a function that resumes the coroutine when called
return coroutine.wrap(function() zipgen(args) end)
end

Lua - how to sort a table by the value chain

I'm looking for a method of sorting a Lua table by its values chain. Say, the table:
local vals = {
{ id = "checkpoint4" },
{ id = "checkpoint1", nextid = "checkpoint2" },
{ id = "checkpoint3", nextid = "checkpoint4" },
{ id = "checkpoint2", nextid = "checkpoint3" },
}
Should transform into this after sorting:
local vals = {
{ id = "checkpoint1", nextid = "checkpoint2" },
{ id = "checkpoint2", nextid = "checkpoint3" },
{ id = "checkpoint3", nextid = "checkpoint4" },
{ id = "checkpoint4" },
}
It's not essentially with the exact same names, they might vary. I wanted to make the comparison of numbers after "checkpoint", but it turned out that I have to work with dynamic things like this (already sorted the way I want it to be):
local vals = {
{ id = "checkpoint1", nextid = "cp" },
{ id = "cp", nextid = "chp" },
{ id = "chp", nextid = "mynextcheckpoint" },
{ id = "mynextcheckpoint"},
}
Thanks.
What you are describing is called topological sorting. However, since this is a restricted case, we do not have to implement a complete topological sorting algorithm:
function sort_list(tbl)
local preceding = {}
local ending
local sorted = {}
for i, e in ipairs(tbl) do
if e.nextid == nil then
ending = e
else
preceding[e.nextid] = i
end
end
if ending == nil then
return nil, "no ending"
end
local j = #tbl
while ending ~= nil do
sorted[j] = ending
ending = tbl[preceding[ending.id]]
j = j - 1
end
if sorted[1] == nil then
return nil, "incomplete list"
end
return sorted
end
Usage:
local sorted = sort_list(vals)
local id2val, tailsizes = {}, {}
for _, val in ipairs(vals) do id2val[val.id] = val end
local function tailsize(val) -- memoized calculation of tails sizes
if not tailsizes[val] then
tailsizes[val] = 0 -- cycle-proof
if val.nextid and id2val[val.nextid] then -- dangling nextid proof
tailsizes[val] = tailsize(id2val[val.nextid]) + 1
end
end
return tailsizes[val]
end
-- sorting according to tails sizes
table.sort(vals, function(a,b) return tailsize(a) > tailsize(b) end)

how to sort a table in lua?

I have a lua table that contains 2 key pieces of data. I would like to sort the table in ascending order by the "num1" column, or if thats not possible, they by the key value in ascending order
Here's what I have so far:
local widgets = {}
widgets[1568] = {}
widgets[1568]["num1"] = 99999
widgets[1568]["val2"] = "NA"
widgets[246] = {}
widgets[246]["num1"] = 90885
widgets[246]["val2"] = "NA"
widgets[250] = {}
widgets[250]["num1"] = 95689
widgets[250]["val2"] = "NA"
widgets[251] = {}
widgets[251]["num1"] = 95326
widgets[251]["val2"] = "NA"
widgets[252] = {}
widgets[252]["num1"] = 95301
widgets[252]["val2"] = "NA"
widgets[256] = {}
widgets[256]["num1"] = 95303
widgets[256]["val2"] = "NA"
-- ATTEMPT TO SORT
--table.sort(widgets, function(a,b) return tonumber(a.num1.value) < tonumber(b.num1.value) end)
--table.sort(widgets, function(a,b) return tonumber(a.num1) < tonumber(b.num1) end)
--TRY SORTING BY ID:
table.sort(widgets, function(a,b) return tonumber(a) < tonumber(b) end)
for i, v in pairs(widgets) do
print(v.num1)
end
Any suggestions would be appreciated. Right now, I'm reviewing Sort a Table[] in Lua to try to understand the "spairs" function. But that example is slightly different because I have a table within a table...
Thanks.
SOLUTION
In line with the answer below, I created a new table and added the records from the old table, one by one, using table insert like so:
local new_widgets = {}
for i, v in pairs(widgets) do
table.insert(new_widgets, id=v.id, num1= v.num1, num2 = v.num2)
end
then I sorted new_wigets.
Lua tables are hashtables. Their entries have no specific order.
You fake it by using consecutive numerical indices then iterating by incrementing a number (note: internally Lua actually will implement this as an array, but that's an implementation detail; conceptually, table entries have no specific order).
t[2] = "two"
t[3] = "three"
t[1] = "one"
for i=1,#t do print(t[i]) end
ipairs creates an iterator that does the same thing as this for loop.
So, if you want your data sorted, you need to put it in a table with consecutive numeric indices.
In your case, there's a lot of different ways you can do it. Here's one way to skin that cat:
Instead of this:
local widgets = {
[246] = { num1 = 90885, val2 = "NA" }
[250] = { num1 = 95689, val2 = "NA" }
[251] = { num1 = 95326, val2 = "NA" }
[252] = { num1 = 95301, val2 = "NA" }
[256] = { num1 = 95303, val2 = "NA" }
}
You want this:
local widgets = {
{ id = 246, num1 = 90885, val2 = "NA" },
{ id = 250, num1 = 95689, val2 = "NA" },
{ id = 251, num1 = 95326, val2 = "NA" },
{ id = 252, num1 = 95301, val2 = "NA" },
{ id = 256, num1 = 95303, val2 = "NA" },
}
-- sort ascending by num1
table.sort(widgets, function(a,b) return a.num1 < b.num1 end)
for i, widget in ipairs(widgets) do
print(widget.num1)
end
If you need the ability to then lookup a widget quickly by id, you can create a lookup table for that:
local widgetById = {}
for i,widget in pairs(widgets) do
widgetById[widget.id] = widget
end

generating TTT game tree in lua

I am attempting to write a tic-tac-toe game in lua, and plan on using the minimax algorithm to decide non-human moves. The first step in this involves generating a tree of all possible board states from a single input state. I am trying to recursively do this, but cannot seem to figure out how. (I think) I understand conceptually how this should be done, but am having trouble implementing it in lua.
I am trying to structure my tree in the following manner. Each node is a list with two fields.
{ config = {}, children = {} }
Config is a list of integers (0,1,2) that represent empty, X, and O and defines a TTT board state. Children is a list nodes which are all possible board states one move away from the current node.
Here is my function that I currently have to build the game tree
function tree_builder(board, player)
supertemp = {}
for i in ipairs(board.config) do
--iterate through the current board state.
--for each empty location create a new node
--representing a possible board state
if board.config[i] == 0 then
temp = {config = {}, children = {}}
for j in ipairs(board.config) do
temp.config[j] = board.config[j]
end
temp.config[i] = player
temp.children = tree_builder(temp, opposite(player))
supertemp[i] = temp
end
end
return supertemp
end
The function is called in the following manner:
start_board = {config = {1,0,0,0}, children = {} }
start_board.children = tree_builder(start_board, 1)
When I comment out the recursive element of the function (the line "temp.children = builder(temp, opposite(player))") and only generate the first level of children. the output is correct. When called via code that is conceptually identical to (I am using love2D so formatting is different):
for i in pairs(start_board.children) do
print (start_board.children[i].config)
The three children are:
1,1,0,0
1,0,1,0
1,0,0,1
However, once I add the recursive element, the following is output for the same three children
1,1,2,1
1,1,2,1
1,1,2,1
I have been searching online for help and most of what I have found is conceptual in nature or involves implementation in different languages. I believe I have implemented the recursive element wrongly, but cannot wrap my head around the reasons why.
Don't understand what opposite(player) means in temp.children = tree_builder(temp, opposite(player)).
Notice that a recursion need an end condition.
This is my solution under your structure:
local COL = 3
local ROW = 3
local function printBoard( b )
local output = ""
local i = 1
for _,v in ipairs(b.config) do
output = output .. v .. ( (i % COL == 0) and '\n' or ',' )
i = i + 1
end
print( output )
end
local function shallowCopy( t )
local t2 = {}
for k,v in pairs(t) do
t2[k] = v
end
return t2
end
local MAX_STEP = COL * ROW
local ING = 0
local P1 = 1
local P2 = 2
local TIE = 3
local STATUS = { [P1] = "P1 Win", [P2] = "P2 Win", [TIE] = "Tied" }
local start_board = { config = {P1,0,0,0,0,0,0,0,0}, children = {} }
local function checkIfOver( board, step )
local config = board.config
local over = false
--check rows
for i=0,ROW-1 do
over = true
for j=1,COL do
if 0 == config[i*COL+1] or config[i*COL+j] ~= config[i*COL+1] then
over = false
end
end
if over then
return config[i*COL+1]
end
end
--check cols
for i=1,COL do
over = true
for j=0,ROW-1 do
if 0 == config[i] or config[i] ~= config[i+COL*j] then
over = false
end
end
if over then
return config[i]
end
end
--check diagonals
if config[1] ~= 0 and config[1] == config[5] and config[5] == config[9] then
return config[1]
end
if config[3] ~=0 and config[3] == config[5] and config[5] == config[7] then
return config[3]
end
if step >= MAX_STEP then
return TIE
else
return ING
end
end
local function treeBuilder( board, step )
--check the game is over
local over = checkIfOver( board, step )
if over ~= ING then
printBoard( board )
print( STATUS[over], '\n---------\n' )
return
end
local child
local childCfg
for i,v in ipairs(board.config) do
if 0 == v then
child = { config = {}, children = {} }
childCfg = shallowCopy( board.config )
childCfg[i] = (step % 2 == 0) and P1 or P2
child.config = childCfg
table.insert( board.children, child )
treeBuilder( child, step + 1 )
end
end
end
treeBuilder( start_board, 1 )

Resources