Is it possible that key has multi values on Lua script - lua

I want to handle lua table.
Script:
local my_talbe = {}
for key, value in pairs(my_table)
print(key, value)
end
The script returns:
a 80
b 80
c 70
d 40
e 70
f 80
I want to my_table handle like this:
local new_talbe = {}
for key, value in pairs(new_table)
print(key, value)
end
Expected output:
80 {a,b,f} # table
70 {c,e}
40 {d}
Please help me.

If you can change how my_table is created, use #pynexj method.
If you need to convert, something like this should do the job.
local my_table = {
a = 80,
b = 80,
c = 70,
d = 40,
e = 70,
f = 80,
}
-- Invert key and value, but put the keys into buckets/arrays
local function to_multi_key_map(t)
local n = { }
for i,v in pairs(t) do
if n[v] then
table.insert(n[v], i)
else
n[v] = { i }
end
end
return n
end
for i,v in pairs(to_multi_key_map(my_table)) do
print(i, "{" .. table.concat(v, ", ") .. "}")
end
70 {c, e}
80 {b, f, a}
40 {d}

Related

Unpack lua table as object and map them as function arguments

I'm looking for a way to unpack lua table(object, not an array) and map return value as arguments to a function.
Example:
local function f(a, b, c, d)
print(a, b, c, d)
end
--order is messed up on purpose
local object_to_unpack = {
a = 1,
c = 42,
d = 18,
b = 102
}
So Im looking for a way to do something like
f(unpack_and_map(object_to_unpack)) and for function to output 1, 102, 42, 18.
I know about unpack function, but it only works on arrays, not objects, and I don't have any ordering guarantees(as demonstrated in object_to_unpack)
Not sure why you want to unpack that table and not just use it as the functions parameter.
local someTable = {
a = 1,
c = 42,
d = 18,
b = 102,
}
local function f(t)
print(t.a, t.b, t.c, t.d)
end
f(someTable)
If you insist on calling f with a list of expressions you need to create one.
function f(...)
print(...)
end
local args = {}
for _, v in pairs(someTable) do
table.insert(args, v)
end
f(table.unpack(args))
This does not guarantee any order. If you want the list ordered by the keys you need to sort that list prior to calling f.
local keys = {}
for k in pairs(someTable) do
table.insert(keys, k)
end
table.sort(keys)
local args = {}
for _, key in ipairs(keys) do
table.insert(args, someTable[key])
end
f(table.unpack(args))

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.

multi key tuple to map a multi value tuple in Lua

Is there a lib in Lua that supports a map from a tuple to a tuple? I have a key {a,b,c} to map to a value {c,d,e}
There are libs such as, http://lua-users.org/wiki/MultipleKeyIndexing for multikey but not where the value is a tuple.
Here's one way to use Egor's suggestion for making a key through string concatenation. Make your own simple insert and get methods for a table, t.
local a, b, c = 10, 20, 30
local d, e, f = 100, 200, 300
local t = {}
t.key = function (k)
local key = ""
for _,v in ipairs(k) do
key = key .. tostring(v) .. ";"
end
return key
end
t.set = function (k, v)
local key = t.key(k)
t[key] = v
end
t.get = function (k)
local key = t.key(k)
return t[key]
end
t.set ({a, b, c}, {d, e, f}) -- using variables
t.set ({40, 50, 60}, {400, 500, 600}) -- using constants
local w = t.get ({a, b, c}) -- using variables
local x = t.get ({40, 50, 60}) -- using constants
print(w[1], w[2], w[3]) -- 100 200 300
print(x[1], x[2], x[3]) -- 400 500 600

Reversing an decode function

I'm trying to reverse a decode function. This function takes a string and a key and encodes the string with that key. This is the code:
function decode(key, code)
return (code:gsub("..", function(h)
return string.char((tonumber(h, 16) + 256 - 13 - key + 255999744) % 256)
end))
end
If I input 7A as code and 9990 as key, it returns g
I tried reversing the operators and fed back the output of the decode function but I get an error becauase tonumber() returns nil. How can I reverse this function?
By using the answer to this Lua base coverter and flipping the operators of the decode function, I was able to convert back the input.
This is the whole code:
function encodes(key, code)
return (code:gsub("..", function(h)
return string.char((tonumber(h, 16) + 256 - 13 - key + 255999744) % 256)
end))
end
local floor,insert = math.floor, table.insert
function basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return sign .. table.concat(t,"")
end
function decodes(key, code)
return (code:gsub(".", function(h)
out = (string.byte(h) - 256 + 13 + key - 255999744) % 256
return basen(out,16)
end))
end
a = encodes(9999, "7c7A")
print(a) --prints: `^
print("----------")
b = decodes(9999, a)
print(b) --prints: 7C7A

Lua table.concat

Is there a way to use the arg 2 value of table.concat to represent the current table index?
eg:
t = {}
t[1] = "a"
t[2] = "b"
t[3] = "c"
X = table.concat(t,"\n")
desired output of table concat (X):
"1 a\n2 b\n3 c\n"
Simple answer : no.
table.concat is something really basic, and really fast.
So you should do it in a loop anyhow.
If you want to avoid excessive string concatenation you can do:
function concatIndexed(tab,template)
template = template or '%d %s\n'
local tt = {}
for k,v in ipairs(tab) do
tt[#tt+1]=template:format(k,v)
end
return table.concat(tt)
end
X = concatIndexed(t) -- and optionally specify a certain per item format
Y = concatIndexed(t,'custom format %3d %s\n')
I don't think so: how would you tell it that the separator between keys and values is supposed to be a space, for example?
You can write a general mapping function to do what you'd like:
function map2(t, func)
local out = {}
for k, v in pairs(t) do
out[k] = func(k, v)
end
return out
end
function joinbyspace(k, v)
return k .. ' ' .. v
end
X = table.concat(map2(t, joinbyspace), "\n")
No. But there is a work around:
local n = 0
local function next_line_no()
n = n + 1
return n..' '
end
X = table.concat(t,'\0'):gsub('%f[%Z]',next_line_no):gsub('%z','\n')
function Util_Concat(tab, seperator)
if seperator == nil then return table.concat(tab) end
local buffer = {}
for i, v in ipairs(tab) do
buffer[#buffer + 1] = v
if i < #tab then
buffer[#buffer + 1] = seperator
end
end
return table.concat(buffer)
end
usage tab is where the table input is and seperator be both nil or string (if it nil it act like ordinary table.concat)
print(Util_Concat({"Hello", "World"}, "_"))
--Prints
--Hello_world

Resources