find all possible combination of these two sets of items? Lua - 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.

Related

map varargs function lua

I want to be able to map functions that take multiple arguments like
function(a, b) return a+b end
onto a table so that I can write stuff like
answer = varmap(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}
but I am not comfortable with lua varargs and the code samples on wikibooks use table.getn, and when you replace them with # it doesn't work and returns "attempt to preform arithmatic on local 'a' (a nil value)"
One more possibility:
local unpack = table.unpack or unpack
--------------------------------------------------------------------------------
-- 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 ans
end
end
--------------------------------------------------------------------------------
function map(f,...)
assert(type(f) == 'function','Function expected for 1st arg')
local t = {...}
return coroutine.wrap(
function()
for t in zip(unpack(t)) do
coroutine.yield(f(unpack(t)))
end
end)
end
--------------------------------------------------------------------------------
-- Example use
for item in map(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}) do
print(item)
end
print()
for item in map(function(a) return a*2 end, {1, 7, 3}) do
print(item)
end
local function imap(func, ...) -- imap(func, src_table_1, src_table_2, ...)
local result = {}
local src_tables_arr = {...}
if #src_tables_arr == 1 then
for k, v in ipairs(src_tables_arr[1]) do
result[k] = func(v)
end
else
for k = 1, #src_tables_arr[1] do
result[k] = func(
(table.unpack or unpack)
(
imap(
function(src_t) return src_t[k] end,
src_tables_arr
)
)
)
end
end
return result
end
table.imap = imap
Usage:
local arr = table.imap(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
Perhaps you are looking for something like this:
function varmapn(func, ...)
local args, result = { ... }, {}
for arg_i = 1, #(args[1]) do
local call_args = {}
for arg_list = 1, #args do
table.insert(call_args, args[arg_list][arg_i])
end
table.insert(result, func(table.unpack(call_args)))
end
return result
end
Sample interaction:
> answer = varmapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> print(answer)
table: 0x970eb0
> for i = 1, 3 do print(answer[i]) end
6
11
11
Or, here is a slightly more involved function that is more general. For argument lists it takes arrays, or it takes tables with arbitrary keys:
function mapn(func, ...)
local args, call_args = { ... }, {}
local result = {}
for k in pairs(args[1]) do
call_args[k] = {}
end
for arg_list, v in pairs(args) do
for k in pairs(args[1]) do
table.insert(call_args[k], v[k])
end
end
for k, v in pairs(call_args) do
result[k] = func(table.unpack(v))
end
return result
end
Sample interaction:
> answer = mapn(function (a, b) return a+b end, {x=1, y=7, z=3}, {x=5, y=4, z=8})
> for k,v in pairs(answer) do print(k .. " = " .. v) end
z = 11
y = 11
x = 6
> answer = mapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> for i = 1, 3 do print(answer[i]) end
6
11
11

How do you do the Fisher-Yates shuffle in Lua

I've been asking questions on random numbers, and I decide the Fisher-Yates shuffle would be the best option. I make a table 't'
t = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Now, how would I even shuffle these and be able to use them individually, for example generate the results in another table u
u = {}
For those that find this answer later, this will shuffle in place without making a new table:
local function ShuffleInPlace(t)
for i = #t, 2, -1 do
local j = math.random(i)
t[i], t[j] = t[j], t[i]
end
end
And this one that returns a shuffled table without touching the original (unlike the current answer, which both shuffles in-place and returns a copy):
local function Shuffle(t)
local s = {}
for i = 1, #t do s[i] = t[i] end
for i = #t, 2, -1 do
local j = math.random(i)
s[i], s[j] = s[j], s[i]
end
return s
end
Usage:
local t = {"a", "b", "c", "d", "e", "f"}
print(table.concat(t)) --> abcdef
local s = Shuffle(t)
print(table.concat(t)) --> abcdef (unchanged)
print(table.concat(s)) --> fbcade (shuffled)
ShuffleInPlace(t)
print(table.concat(t)) --> dcbfea (shuffled)
And a quick sanity check that they're uniform:
local t = {"a", "b", "c"}
local results = {abc = 0,acb = 0,bac = 0,bca = 0,cab = 0,cba = 0}
for i = 1, 10000000 do
ShuffleInPlace(t)
local r = table.concat(t)
results[r] = results[r] + 1
end
for k, v in pairs(results) do print(k, v) end
--[[
cba 1667473
cab 1666235
bca 1665672
bac 1666782
acb 1666447
abc 1667391
--]]
NOTE: Check the other answer https://stackoverflow.com/a/68486276/1190388 which fixes an issue in the code snippet below as well as providing other alternatives
If you do not have holes in your table:
math.randomseed(os.time()) -- so that the results are always different
function FYShuffle( tInput )
local tReturn = {}
for i = #tInput, 1, -1 do
local j = math.random(i)
tInput[i], tInput[j] = tInput[j], tInput[i]
table.insert(tReturn, tInput[i])
end
return tReturn
end

Why won't __add work?

So I am trying to learn about metatables in lua, so i decided to follow some tutorials. I was trying out the __add part of metatables. But for some reason i kept on getting an error (attempt to perform arithmetic on field (nil)
aTable = {}
--Assign the values for the normal table
for x = 1, 10 do
aTable[x] = x
end
-- metatable
mt = {__add = function(table1, table2)
sumTable = {}
for i = 0, #table1 do
sumTable[i] = table1[i] + table2[i]
end
return sumTable
end}
setmetatable(aTable, mt)
newTable = {}
newTable = aTable + aTable
for x = 1, #newTable do
print(newTable[x])
end
At this point i am confused.Help would be appreciated
In the __add-function it should be:
for i = 1, #table1 do
since you didn't set table[0] initially, but started at index 1 (which is indeed recommended for lua-pseudoarrays, many operations rely on it)
#Ctx is correct that the problem is that differing indices in the array initialization and adding functions. But the best way to fix it is to modify your __add function to handle 'holes' in the arrays passed, by checking for nil entries in them.
for i = 0, #table1 do
if (table1[i] and table2[i]) then
sumTable[i] = table1[i] + table2[i]
end
end
Another thing that's missing: You don't set the same metatable on the result, which means that while things like aTable+aTable, aTable+aTable+aTable etc. will work, aTable+aTable+(aTable+aTable) will fail.
Corrected and cleaned version:
-- metatable
mt = {
__add = function( table1, table2 )
sumTable = {}
for i = 1, #table1 do
sumTable[i] = table1[i] + table2[i]
end
return setmetatable( sumTable, mt )
end,
}
aTable = setmetatable( {}, mt )
--Assign the values for the normal table
for x = 1, 10 do aTable[x] = x end
newTable = aTable + aTable
for x = 1, #newTable do print( newTable[x] ) end
-- and a test for what would have failed:
yetAnotherTable = newTable + newTable
for x = 1, #yetAnotherTable do print( yetAnotherTable[x] ) end

How to shift all elements in a table?

I'm trying to think of an easy way to make all elements in a table shift up one. It is for a game I am playing, attempting to switch between all targets in a table!
For example, let's say I'm surrounded by three mooks who want to kill me, so I target all of them and they're added into an array like so:
{
"mook1",
"mook2",
"mook3",
}
What I want the function to do is change all indexes to go up one (or the amount I specify), and the last to go to the beginning, so the end result would be:
{
"mook3",
"mook1",
"mook2",
}
I attempted it on my own with a simple function like this:
local function nextIndex(tbl, amount)
local t = {}
for k,v in ipairs(tbl) do
if k < #tbl then
t[k+amount] = v
else
t[1] = v
end
end
return t
end
It works as long as the amount is set to 1. I'm sure there is a much smarter and more efficient way of doing this. Could anyone take a whack at it please?!
You can use a function like this:
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, table.remove( t, #t ) )
end
end
You can see a test run on codepad. or, if you're uncomfortable with nesting of function calls;
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, t[#t] )
table.remove( t, #t )
end
end
would work the same way.
I worked a bit more and figured out how to do it. This is the code:
local function nextIndex(tbl, amount)
local t = {}
local i
for k,v in ipairs(tbl) do
i = k + amount
if i <= #tbl then
t[i] = v
else
t[i-#tbl] = v
end
end
return t
end
Is there an easier way to do it though?
So, the task is to rotate the last rot items to the front.
I added parameter n to allow overriding of the sequence end as determined by #t.
-- uses t[#t+1]...t[#t+rot%#t] as scratch space
local function rotate_mod(t, rot, n)
n = n or #t
rot = rot % n
if rot == 0 then return t end
for i = n, 1, -1 do
t[i + rot] = t[i]
end
for i = 1, rot do
t[i], t[i + n] = t[i + n]
end
return t
end
Or if you want a new array (just ignore parameter r):
local function rotate_new(t, rot, n, r)
n, r = n or #t, {}
rot = rot % n
for i = 1, rot do
r[i] = t[n - rot + i]
end
for i = rot + 1, n do
r[i] = t[i - rot]
end
return r
end
Here's a true "in-place" version. It does not need to temporarily enlarge the table:
local function reverse(t, i, j)
while i < j do
t[i], t[j] = t[j], t[i]
i, j = i+1, j-1
end
end
local function rotate_inplace(t, d, n)
n = n or #t
d = (d or 1) % n
reverse(t, 1, n)
reverse(t, 1, d)
reverse(t, d+1, n)
end

Lua table constructor values as multi-value-return function calls

Using Lua (5.1) I would like to fill the table with functions which return several values. Unfortunately, due to Lua specification such function call will only be expanded for the last one.
function get2() return 1, 2 end
local t = { get2(), get2() }
for _,v in pairs(t) do print(v) end
Returns: 1, 1, 2
Is there any way of doing this besides
table = {};
res1, res2 = get2();
table[#table + 1] = res1;
table[#table + 1] = res2
or some other convoluted technique?
No, there is no direct way to do this.
But you can simplify the code with a helper function.
function get2() return 1, 2 end
function appendMultiple(t, ...)
for i=1, select('#', ...) do
t[#t+1] = select(i, ...)
end
end
local t = { }
appendMultiple(t, get2())
appendMultiple(t, get2())
for _,v in pairs(t) do print(v) end
--> 1 2 1 2

Resources