Files
Techmino/Zframework/tableExtend.lua
2023-12-04 20:02:12 +08:00

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