How does one reverse the items in a table in Lua? - lua

Is there something that would do the same thing as table.sort, but backwards?

The table.sort function allows you to define a sorting function as the second argument. It returns a boolean and specifies the order on which the table must be ordered:
local atable = {1,2,3}
table.sort(atable, function(a,b) return a > b end)
for _, v in pairs(atable) do
print(v)
end
--[[This prints:
3
2
1
]]
Of course, this doesn't limit itself to "lists" but you can use them on other table types as well:
local cityInfo = {
{name = "Vancouver", population = 321, location = "Canada"},
{name = "Paris", population = 123, location = "France"},
{name = "London", population = 1000, location = "United Kingdom"},
}
table.sort(cityInfo, function(a,b) return a.population > b.population end) -- Here the items are ordered in descencing order based on the population field
for _, v in pairs(cityInfo) do
print(v.population)
end
--[[This prints:
1000
321
123
]]

If you want to sort a table in reverse order:
table.sort(your_table, function(x, y) return x > y end)
If you want to reverse a table:
local function reverse(tab)
for i = 1, #tab//2, 1 do
tab[i], tab[#tab-i+1] = tab[#tab-i+1], tab[i]
end
return tab
end

Related

Remove a object from a table listed inside a different table

So i have 2 tables
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
I want remove the number in table 2 from table 1, to then use table one with the numbers removed in more code. How would i go about doing this?
When you read the data into the table, set the value of the index of whatever you are reading in as the key in the table. This avoids collisions and allows easy comparisons against another table.
local table1 = {}
local table2 = {}
-- read in your values as keys into the two tables
-- just an example I have no idea how you are populating the tables but hope it helps
table1 = {['input1'] = 0, ['input6'] = 0, ['input3'] = 0}
table2 = {['input1'] = 0, ['input3'] = 0}
newTable = {}
function tableHasKey(table, key)
return table[key] ~= nil
end
for key, _ in pairs(table1) do
if not tableHasKey(table2, key) then
table.insert(newTable, key)
end
end
for _, value in pairs(newTable) do
print(value)
end
The result is 'input6' when I run this. Which means all values not in table2 that are in table1 are now in newTable. If the values are unique between tables it's easier to compare keys than values. The final result is an indexed table where the result is stored in the value of the hash object.
#! /usr/bin/env lua
local table1 = {1,2,3,4,5,6,7,8,9}
local table2 = {2,4,6,8}
for number = 1, #table1 do
for delete = 1, #table2 do
if table1[number] == table2[delete] then
for i = number, #table1 -1 do
table1[i] = table1[i +1]
end -- shuffle every entry in table down
table1 [#table1] = nil -- erase last entry
end -- number == delete
end -- loop through table2
end -- loop through table1
for i = 1, #table1 do print( table1[i] ) end
1
3
5
7
9
The other answers listed here seem correct, but they seem a little too aggressive on memory or time complexity. Here's my take on a filter function optimized for lists of numbers.
-- t1 : table, the original set of values
-- t2 : table, the set of values to remove from t1
-- returns : table, a subset of elements from t1 not found in t2
local function filter(t1, t2)
-- Assumptions :
-- 1) t1 and t2 are arrays, not dictionaries
-- 2) t1 and t2 do not have mixed indices or mixed values
-- 3) t1 and t2 are sorted
assert(type(t1) == "table", "t1 expected to be a table")
assert(type(t2) == "table", "t2 expected to be a table")
assert(type(next(t1)) == "number" or type(next(t1)) == "nil", "t1 expected to be an array")
assert(type(next(t2)) == "number" or type(next(t2)) == "nil", "t2 expected to be an array")
-- Early Outs :
if #t1 == 0 then
return {}
elseif #t2 == 0 then
return t1
end
-- step through each list and compare each index as you go
local filteredT = {}
local i = 1
local j = 1
local sizeT1 = #t1
local sizeT2 = #t2
while (i <= sizeT1) and (j <= sizeT2) do
if t1[i] == t2[j] then
-- found a match, exclude from output
i = i + 1
j = j + 1
elseif t1[i] < t2[j] then
-- no match, add elements from t1
table.insert(filteredT, t1[i])
i = i + 1
else -- t1[i] > t2[j]
-- no match, ignore elements from t2
j = j + 1
end
end
-- we've made it to the end of one of the lists, add the rest of t1
for i = i, sizeT1, 1 do
table.insert(filteredT, t1[i])
end
return filteredT
end
This solution doesn't have unnecessary loop iterations and a number of early outs for optimization.
local a = {1,2,3,4,5,6,7,8,9}
local b = {2,4,6,8}
local result1 = filter(a, b)
print(table.concat(result1, ", ")) -- 1, 3, 5, 7, 9
local c = {"a", "b", "c", "d"}
local d = {"c", "d"}
local result2 = filter(c, d)
print(table.concat(result2, ", ")) -- "a", "b"

find all possible combination of these two sets of items? Lua

I see similar answers to this question given in different programming languages like Haskell and Python but all of them use build-in functionality that Lua doesn't have, so please don't mark this question as duplicate.
Let's say i have two tables like bellow:
table1 = {A,B,C}
table2 = {D,E,F}
I would like to find all unique ways of matching the items from two tables, the answer should be (in informal notation):
AD,BE,CF
AD,BF,CE
AE,BD,CF
AE,BF,CD
AF,BD,CE
AF,BE,CD
so the answer will store in a table that table[1] would be {{A, D}, {B, E}, {C, F}} and so on.
tables length can be anything but both will be the same size.
we can get all shuffles via induction (not the fastest way, but pretty easy to write/understand)
local function deepcopy(orig)
local copy
if type(orig) == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else
copy = orig
end
return copy
end
local function get_shuffles(N)
if N == 1 then
return {{1}}
end
local shuffles = get_shuffles(N-1)
local result = {}
for index = 1, #shuffles do
local shuffle = shuffles[index]
for position = 1, #shuffle do
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, position, N)
table.insert(result, new_shuffle)
end
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, N)
table.insert(result, new_shuffle)
end
return result
end
table1 = {"A", "B", "C"}
table2 = {"D","E", "F"}
assert(#table1 == #table2)
local result = {}
local shuffles = get_shuffles(#table1)
for index = 1, #shuffles do
local shuffle = shuffles[index]
local part = {}
for i = 1, 3 do
table.insert(part, {})
table.insert(part[i], table1[i])
table.insert(part[i], table2[shuffle[i]])
end
table.insert(result, part)
end
for index = 1, #result do
print(result[index][1][1], result[index][1][2], result[index][2][1], result[index][2][2], result[index][3][1], result[index][3][2])
end
function get_all_combinations(arr1, arr2)
local n, e, all_comb = #arr1, {}, {}
for j = 1, n do
e[j] = arr2[j]
end
local function generate(m)
if m <= 1 then
local comb = {}
all_comb[#all_comb + 1] = comb
for j = 1, n do
comb[j] = arr1[j]..e[j] -- it should be {arr1[j], e[j]} to fulfill your requirements
end
else
for j = 1, m do
generate(m - 1)
local k = j < m and m % 2 == 1 and 1 or j
e[k], e[m] = e[m], e[k]
end
end
end
generate(n)
return all_comb
end
for i, v in ipairs(get_all_combinations({"A", "B", "C"}, {"D", "E", "F"})) do
print(i, table.concat(v, ";"))
end
An alternate way of doing it is with the following code. This was written to help with a game (Typeshift) to discover all possible combinations of variable groups of letters. I've modified it to fit your example, though.
-- table array: { {1, 2}, {3, 4}, {5, 6} }
-- Should return { 135, 136, 145, 146, 235, 236, 245, 246 }
--
-- This uses tail recursion so hopefully lua is smart enough not to blow the stack
function arrayCombine(tableArray)
-- Define the base cases
if (tableArray == nil) then
return nil
elseif (#tableArray == 0) then
return {}
elseif (#tableArray == 1) then
return tableArray[1]
elseif (#tableArray == 2) then
return arrayCombine2(tableArray[1], tableArray[2])
end -- if
-- We have more than 2 tables in the input parameter. We want to pick off the *last*
-- two arrays, merge them, and then recursively call this function again so that we
-- can work our way up to the front.
local lastArray = table.remove(tableArray, #tableArray)
local nextToLastArray = table.remove(tableArray, #tableArray)
local mergedArray = arrayCombine2(nextToLastArray, lastArray)
table.insert(tableArray, mergedArray)
return arrayCombine(tableArray)
end -- arrayCombine
function arrayCombine2(array1, array2)
local mergedArray = {}
for _, elementA in ipairs(array1) do
for _, elementB in ipairs(array2) do
table.insert(mergedArray, elementA .. elementB)
end -- for
end -- for
return mergedArray
end -- arrayCombine2
-- You can set it up this way:
combinedArray = {}
table.insert(combinedArray, {"A", "B", "C"})
table.insert(combinedArray, {"D", "E", "F"})
for i,v in ipairs(arrayCombine(combinedArray)) do
print(i,v)
end
-- Or go this way, which may be somewhat cleaner:
for i,v in ipairs(arrayCombine({{"A", "B", "C"}, {"D", "E", "F"}})) do
print(i,v)
end
Either way, it produces the results you're looking for.

Calling table.sort returns nil

I am trying to sort a table 'array' that contains tables with two keys called 'pt' and 'angle'. I want to sort the 'array' elements regarding their 'angle' value. To my understanding of table.sort this code snippet should do the trick:
local array = {}
-- Some code that calls
-- table.insert(array, {pt = somePt, angle = someAngle})
-- multiple times
local sorted_table = table.sort(array, function(a,b) return a.angle < b.angle end)
However, sorted_table is always nil. Am I doing something wrong here?
table.sort sorts the array part of a table in place. It does not return a new array. If you need to keep the original, you first need to copy to a temporary array.
So, try something like this:
table.sort(array,function(a,b) return a.angle < b.angle end)
table.sort sorts the table in place; that is, it changes the table that you give it and doesn't return a new one.
If you want a sorted copy, you'd first have to make a copy of the table yourself, then sort it.
This could look like this:
local function sorted_copy(tab, func)
local tab = {table.unpack(tab)}
table.sort(tab, func)
return tab
end
That will create a copy of the table (at least the numeric indices up to some random border) and sort it.
there is no secret, there is an algorithm for this sorting, which has been used many times:
function quicksort(t, sortname, start, endi)
start, endi = start or 1, endi or #t
sortname = sortname or 1
if(endi - start < 1) then return t end
local pivot = start
for i = start + 1, endi do
if t[i][sortname] <= t[pivot][sortname] then
local temp = t[pivot + 1]
t[pivot + 1] = t[pivot]
if(i == pivot + 1) then
t[pivot] = temp
else
t[pivot] = t[i]
t[i] = temp
end
pivot = pivot + 1
end
end
t = quicksort(t, sortname, start, pivot - 1)
return quicksort(t, sortname, pivot + 1, endi)
end
local array = {}
table.insert(array, {pt = 1, angle = 2})
table.insert(array, {pt = 4, angle = 9})
table.insert(array, {pt = 1, angle = 5})
table.insert(array, {pt = 2, angle = 7})
table.insert(array, {pt = 2, angle = 1})
table.insert(array, {pt = 5, angle = 2})
local s_t = quicksort(array, "angle")
for k,v in pairs(s_t) do
print(k, "v=", v.pt, v.angle)
end
Output:
1 v= 2 1
2 v= 5 2
3 v= 1 2
4 v= 1 5
5 v= 2 7
6 v= 4 9

Why is my lua table object empty?

I create a lua table object called Map in my Map module, and this function creates a new instance:
function Map:new (o)
o = o or {
centers = {},
corners = {},
edges = {}
}
setmetatable(o, self)
self.__index = self
return o
end
and in my island module I put in this code in the first few lines:
local map = require (*map module location*)
Island = map:new ()
and when I print the number of centers, corners, and tables, they all come out to 0.
I have separate modules for Corner:new (), Center:new (), and Edge:new ()
Why does the length of centers, corners, and edges output as 0?
Edit:
This is what I input into the centers table for example(corners and edges is similar)
function pointToKey(point)
return point.x.."_"..point.y
end
function Map:generateCenters(centers)
local N = math.sqrt(self.SIZE)
for xx = 1, N do
for yy = 1, N do
local cntr = Center:new()
cntr.point = {x = 0.5+xx - 1, y = 0.5+yy - 1}
centers[pointToKey(cntr.point)] = cntr
end
end
return centers
end
The size is always a perfect square
This seems to be a problem with variable scope. Firstly, in instantiating a new Map, the o that is returned should be local:
function Map:new (o)
local o = o or { -- this should be local
centers = {},
corners = {},
edges = {}
}
setmetatable(o, self)
self.__index = self
return o
end
When you pass a pointer to a table to Map:generateCenters(), there is no need to return that pointer. The centers have been added to that table:
function Map:generateCenters(centers)
local N = math.sqrt(self.SIZE)
for xx = 1, N do
for yy = 1, N do
local cntr = Center:new()
cntr.point = {x = 0.5+xx - 1, y = 0.5+yy - 1}
centers[pointToKey(cntr.point)] = cntr -- HERE you're adding to the table passed as an argument
end
end
-- return centers --> NO NEED TO RETURN THIS
end
Lastly, you would do:
local map = require( "map" )
local island = map:new()
map:generateCenters( island.centers )
You are saying, "Put the centers into the table pointed to by the table value corresponding to the key called centers in the table called island".
Lastly, note that
local t = island.centers
print( #t )
will still not output the number of elements in the table centers because there are gaps keys (i.e. they don't go {0,1,2,3,4,..} but rather whatever string the pointToKey() function returns ). To count the elements in centers, you could do:
local count = 0
for k,v in pairs( island.centers ) do
count = count + 1
end
print( count )

Count frequency of elements into an array in Lua

I have a table in Lua:
p = {'sachin', 'sachin', 'dravid', 'Dhoni', 'yuvraj', 'kohli'}
I want to count frequency of each name in table .
test1 = {sachin=2, dravid=1, Dhoni=1, yuvraj=1, kohli=1}
I tried this program with lot of for loops .Please see my code
> function exec(ele,p)
count = 0
for k,v in pairs(p) do
if ele == p[k] then
count = count +1
end
end
return count
end
> new_table = {}
> for k,v in pairs(p) do
new_table[v] = exec(v,p)
end
>
> for k,v in pairs(new_table) do
print(k,v)
end
dhone 1
yuvraj 1
kohli 1
sachin 2
dravid 1
I want to do this more efficient way. How can I achieve this?
You can count the frequency like this:
function tally(t)
local freq = {}
for _, v in ipairs(t) do
freq[v] = (freq[v] or 0) + 1
end
return freq
end
And here's another demo example.
Using metatable may be a little unnecessary for this simple case, just showing another option:
local mt = {__index = function() return 0 end}
local newtable = {}
setmetatable(newtable, mt)
for _, v in pairs(p) do
newtable[v] = newtable[v] + 1
end
The metamethod __index above gives the table 0 as the default value.

Resources