464 lines
11 KiB
Lua
464 lines
11 KiB
Lua
local rnd=math.random
|
|
local min,max=math.min,math.max
|
|
local find=string.find
|
|
local ins,rem=table.insert,table.remove
|
|
local next,type=next,type
|
|
local TABLE={}
|
|
|
|
-----------------------[Making Tables]------------------------
|
|
-- Get a new filled table
|
|
function TABLE.new(val,count)
|
|
local L={}
|
|
for i=1,count do
|
|
L[i]=val
|
|
end
|
|
return L
|
|
end
|
|
|
|
-- Get a copy of [1~#] elements
|
|
function TABLE.shift(org,depth)
|
|
if not depth then depth=1e99 end
|
|
local L={}
|
|
for i=1,#org do
|
|
if type(org[i])=='table' and depth>0 then
|
|
L[i]=TABLE.shift(org[i],depth-1)
|
|
else
|
|
L[i]=org[i]
|
|
end
|
|
end
|
|
return L
|
|
end
|
|
|
|
-- Get a full copy of a table, depth=how many layers will be recreate, default to inf
|
|
function TABLE.copy(org,depth)
|
|
if not depth then depth=1e99 end
|
|
local L={}
|
|
for k,v in next,org do
|
|
if type(v)=='table' and depth>0 then
|
|
L[k]=TABLE.copy(v,depth-1)
|
|
else
|
|
L[k]=v
|
|
end
|
|
end
|
|
return L
|
|
end
|
|
|
|
-- Connect [1~#] elements of new to the end of org
|
|
function TABLE.connect(org,new)
|
|
local l0=#org
|
|
for i=1,#new do
|
|
org[l0+i]=new[i]
|
|
end
|
|
return org
|
|
end
|
|
|
|
-- Get a table of two lists connected
|
|
function TABLE.combine(L1,L2)
|
|
local l={}
|
|
local l0=#L1
|
|
for i=1,l0 do l[i]=L1[i] end
|
|
for i=1,#L2 do l[l0+i]=L2[i] end
|
|
return l
|
|
end
|
|
|
|
----------------------[Modifying Tables]----------------------
|
|
|
|
-- For all things in new, push to old
|
|
function TABLE.cover(new,old)
|
|
for k,v in next,new do
|
|
old[k]=v
|
|
end
|
|
end
|
|
|
|
-- For all things in new, push to old
|
|
function TABLE.coverR(new,old)
|
|
for k,v in next,new do
|
|
if type(v)=='table' and type(old[k])=='table' then
|
|
TABLE.coverR(v,old[k])
|
|
else
|
|
old[k]=v
|
|
end
|
|
end
|
|
end
|
|
|
|
-- For all things in org, delete them if it's in sub
|
|
function TABLE.subtract(org,sub)
|
|
for _,v in next,sub do
|
|
while true do
|
|
local p=TABLE.search(org,v)
|
|
if p then
|
|
rem(org,p)
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- For all things in new if same type in old, push to old
|
|
function TABLE.update(new,old)
|
|
for k,v in next,new do
|
|
if type(v)==type(old[k]) then
|
|
if type(v)=='table' then
|
|
TABLE.update(v,old[k])
|
|
else
|
|
old[k]=v
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- For all things in new if no val in old, push to old
|
|
function TABLE.complete(new,old)
|
|
for k,v in next,new do
|
|
if type(v)=='table' then
|
|
if old[k]==nil then old[k]={} end
|
|
TABLE.complete(v,old[k])
|
|
elseif old[k]==nil then
|
|
old[k]=v
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------[Removing Table Values]--------------------
|
|
|
|
-- Pop & return random [1~#] of table
|
|
function TABLE.popRandom(t)
|
|
local l=#t
|
|
if l>0 then
|
|
local r=rnd(l)
|
|
r,t[r]=t[r],t[l]
|
|
t[l]=nil
|
|
return r
|
|
end
|
|
end
|
|
|
|
-- Remove [1~#] of table
|
|
function TABLE.cut(G)
|
|
for i=1,#G do
|
|
G[i]=nil
|
|
end
|
|
end
|
|
|
|
-- Clear table
|
|
function TABLE.clear(G)
|
|
for k in next,G do
|
|
G[k]=nil
|
|
end
|
|
end
|
|
|
|
--------------------[Handling duplicates]---------------------
|
|
|
|
-- Remove duplicated value of [1~#]
|
|
function TABLE.trimDuplicate(org)
|
|
local cache={}
|
|
for i=1,#org,-1 do
|
|
if cache[org[i]] then
|
|
rem(org,i)
|
|
else
|
|
cache[org[i]]=true
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Discard duplicated value
|
|
function TABLE.remDuplicate(org)
|
|
local cache={}
|
|
for k,v in next,org do
|
|
if cache[v] then
|
|
org[k]=nil
|
|
else
|
|
cache[v]=true
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Run length encoder. Input must be a list containing non-nil value(s).
|
|
Example:
|
|
- Input: {1, 1, 2, 2, 2, 1}
|
|
- Output: {{1, 2}, {2, 3}, {1, 1}}
|
|
- This means: "Two 1's in a row", "Three 2's in a row", "One 1 in a row"
|
|
]]
|
|
function TABLE.RLE(org)
|
|
local output={}
|
|
local cur=nil
|
|
local count=0
|
|
|
|
for i=1,#org do
|
|
local item=org[i]
|
|
|
|
if item==cur then
|
|
count=count+1
|
|
else
|
|
if cur then
|
|
ins(output,{cur,count})
|
|
end
|
|
cur=item
|
|
count=1
|
|
end
|
|
end
|
|
|
|
if cur then
|
|
ins(output,{cur,count})
|
|
end
|
|
|
|
return output
|
|
end
|
|
|
|
----------------------[Reversing Tables]----------------------
|
|
|
|
-- Reverse [1~#]
|
|
function TABLE.reverse(org)
|
|
local l=#org
|
|
for i=1,math.floor(l/2) do
|
|
org[i],org[l+1-i]=org[l+1-i],org[i]
|
|
end
|
|
end
|
|
|
|
----------------------[Table Comparison]----------------------
|
|
|
|
-- Check if tow list have same elements
|
|
function TABLE.compare(a,b)
|
|
if #a~=#b then return false end
|
|
if a==b then return true end
|
|
for i=1,#a do
|
|
if a[i]~=b[i] then return false end
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- Check if tow table have same elements
|
|
function TABLE.equal(a,b)
|
|
if #a~=#b then return false end
|
|
if a==b then return true end
|
|
for k,v in next,a do
|
|
if b[k]~=v then return false end
|
|
end
|
|
return true
|
|
end
|
|
|
|
----------------------[Table Operations]----------------------
|
|
|
|
-- Find value in [1~#], like string.find
|
|
function TABLE.find(t,val,start)
|
|
for i=start or 1,#t do if t[i]==val then return i end end
|
|
end
|
|
|
|
-- Get subset of table, like string.sub
|
|
function TABLE.sub(t,i,j)
|
|
local subTable={}
|
|
for k=max(i,1),(j and min(j,#t) or #t) do
|
|
subTable[k-i+1]=t[k]
|
|
end
|
|
return subTable
|
|
end
|
|
|
|
-- Replace value in [1~#], like string.gsub
|
|
function TABLE.gsub(t,v_old,v_new,count,start)
|
|
if not start then start=1 end
|
|
if not count then count=1e99 end
|
|
while t[start] and count>0 do
|
|
if t[start]==v_old then
|
|
t[start]=v_new
|
|
count=count-1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Return next value of [1~#] (by value)
|
|
function TABLE.next(t,val)
|
|
for i=1,#t do if t[i]==val then return t[i%#t+1] end end
|
|
end
|
|
|
|
-- Find value in whole table
|
|
function TABLE.search(t,val)
|
|
for k,v in next,t do if v==val then return k end end
|
|
end
|
|
|
|
-- Replace all value in t
|
|
function TABLE.replace(t,v_old,v_new)
|
|
for k,v in next,t do
|
|
if v==v_old then
|
|
t[k]=v_new
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Re-index string value of a table
|
|
function TABLE.reIndex(org)
|
|
for k,v in next,org do
|
|
if type(v)=='string' then
|
|
org[k]=org[v]
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Return table where keys and values are swapped (useful for hashmap)
|
|
function TABLE.kvSwap(t)
|
|
local output={}
|
|
for k,v in next,t do output[v]=k end
|
|
return output
|
|
end
|
|
|
|
--[[
|
|
Extracts a value from each sub-table in table.
|
|
Example input: ({{name='A'},{name='B'},{name='C'}}, 'name')
|
|
Output: {'A','B'}
|
|
]]
|
|
function TABLE.extract(t,keyName)
|
|
local output={}
|
|
for k,v in next,t do output[k]=v[keyName] end
|
|
return output
|
|
end
|
|
|
|
-- Get element count of table
|
|
function TABLE.getSize(t)
|
|
local size=0
|
|
for _ in next,t do size=size+1 end
|
|
return size
|
|
end
|
|
|
|
-----------------------[Table Rotation]-----------------------
|
|
|
|
-- Copy a rotated matrix table
|
|
function TABLE.rotate(cb,dir)
|
|
local icb={}
|
|
if dir=='R' then-- Rotate CW
|
|
for y=1,#cb[1] do
|
|
icb[y]={}
|
|
for x=1,#cb do
|
|
icb[y][x]=cb[x][#cb[1]-y+1]
|
|
end
|
|
end
|
|
elseif dir=='L' then-- Rotate CCW
|
|
for y=1,#cb[1] do
|
|
icb[y]={}
|
|
for x=1,#cb do
|
|
icb[y][x]=cb[#cb-x+1][y]
|
|
end
|
|
end
|
|
elseif dir=='F' then-- Rotate 180 degree
|
|
for y=1,#cb do
|
|
icb[y]={}
|
|
for x=1,#cb[1] do
|
|
icb[y][x]=cb[#cb-y+1][#cb[1]-x+1]
|
|
end
|
|
end
|
|
end
|
|
return icb
|
|
end
|
|
|
|
----------------------[Table Functions]-----------------------
|
|
|
|
-- Return a function that return a value of table
|
|
function TABLE.func_getVal(t,k)
|
|
return function() return t[k] end
|
|
end
|
|
|
|
-- Return a function that reverse a value of table
|
|
function TABLE.func_revVal(t,k)
|
|
return function() t[k]=not t[k] end
|
|
end
|
|
|
|
-- Return a function that set a value of table
|
|
function TABLE.func_setVal(t,k)
|
|
return function(v) t[k]=v end
|
|
end
|
|
|
|
-------------------------[Table Dump]-------------------------
|
|
|
|
-- Dump a simple lua table (no whitespaces)
|
|
do-- function TABLE.dumpDeflate(L,t)
|
|
local function dump(L)
|
|
if type(L)~='table' then return end
|
|
local s='{'
|
|
local count=1
|
|
for k,v in next,L do
|
|
local T=type(k)
|
|
if T=='number' then
|
|
if k==count then
|
|
k=''
|
|
count=count+1
|
|
else
|
|
k='['..k..']='
|
|
end
|
|
elseif T=='string' then
|
|
if find(k,'[^0-9a-zA-Z_]') then
|
|
k='[\''..k..'\']='
|
|
else
|
|
k=k..'='
|
|
end
|
|
elseif T=='boolean' then k='['..k..']='
|
|
else error("Error key type!")
|
|
end
|
|
T=type(v)
|
|
if T=='number' then v=tostring(v)
|
|
elseif T=='string' then v='\''..v..'\''
|
|
elseif T=='table' then v=dump(v)
|
|
elseif T=='boolean' then v=tostring(v)
|
|
else v='*'..tostring(v)
|
|
end
|
|
s=s..k..v..','
|
|
end
|
|
return s..'}'
|
|
end
|
|
TABLE.dumpDeflate=dump
|
|
end
|
|
|
|
-- Dump a simple lua table
|
|
do-- function TABLE.dump(L,t)
|
|
local tabs=setmetatable({
|
|
[0]='',
|
|
'\t',
|
|
},{__index=function(self,k)
|
|
if k>=626 then error("Too many tabs!") end
|
|
for i=#self+1,k do
|
|
self[i]=self[i-1]..'\t'
|
|
end
|
|
return self[k]
|
|
end})
|
|
local function dump(L,t)
|
|
local s='{\n'
|
|
if not t then
|
|
s='return {\n'
|
|
t=1
|
|
if type(L)~='table' then
|
|
return
|
|
end
|
|
end
|
|
local count=1
|
|
for k,v in next,L do
|
|
local T=type(k)
|
|
if T=='number' then
|
|
if k==count then
|
|
k=''
|
|
count=count+1
|
|
else
|
|
k='['..k..']='
|
|
end
|
|
elseif T=='string' then
|
|
if find(k,'[^0-9a-zA-Z_]') then
|
|
k='[\''..k..'\']='
|
|
else
|
|
k=k..'='
|
|
end
|
|
elseif T=='boolean' then k='['..k..']='
|
|
else k='[\'*'..tostring(k)..'\']='
|
|
end
|
|
T=type(v)
|
|
if T=='number' then v=tostring(v)
|
|
elseif T=='string' then v='\''..v..'\''
|
|
elseif T=='table' then v=dump(v,t+1)
|
|
elseif T=='boolean' then v=tostring(v)
|
|
else v='*'..tostring(v)
|
|
end
|
|
s=s..tabs[t]..k..v..',\n'
|
|
end
|
|
return s..tabs[t-1]..'}'
|
|
end
|
|
TABLE.dump=dump
|
|
end
|
|
|
|
return TABLE
|