Table Utils |
|
Produces a compact, uncluttered representation of a table. Mutual recursion is employed.
function table.val_to_str ( v ) if "string" == type( v ) then v = string.gsub( v, "\n", "\\n" ) if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then return "'" .. v .. "'" end return '"' .. string.gsub(v,'"', '\\"' ) .. '"' else return "table" == type( v ) and table.tostring( v ) or tostring( v ) end end function table.key_to_str ( k ) if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then return k else return "[" .. table.val_to_str( k ) .. "]" end end function table.tostring( tbl ) local result, done = {}, {} for k, v in ipairs( tbl ) do table.insert( result, table.val_to_str( v ) ) done[ k ] = true end for k, v in pairs( tbl ) do if not done[ k ] then table.insert( result, table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) end end return "{" .. table.concat( result, "," ) .. "}" end
Example:
t = {['foo']='bar',11,22,33,{'a','b'}}
print( table.tostring( t ) )
{11,22,33,{"a","b"},foo="bar"} .
ISSUE: this should return a string rather than assume how the user wants to output the text.
-- Print anything - including nested tables function table_print (tt, indent, done) done = done or {} indent = indent or 0 if type(tt) == "table" then for key, value in pairs (tt) do io.write(string.rep (" ", indent)) -- indent it if type (value) == "table" and not done [value] then done [value] = true io.write(string.format("[%s] => table\n", tostring (key))); io.write(string.rep (" ", indent+4)) -- indent it io.write("(\n"); table_print (value, indent + 7, done) io.write(string.rep (" ", indent+4)) -- indent it io.write(")\n"); else io.write(string.format("[%s] => %s\n", tostring (key), tostring(value))) end end else io.write(tt .. "\n") end end
Universal tostring
function table_print (tt, indent, done) done = done or {} indent = indent or 0 if type(tt) == "table" then local sb = {} for key, value in pairs (tt) do table.insert(sb, string.rep (" ", indent)) -- indent it if type (value) == "table" and not done [value] then done [value] = true table.insert(sb, "{\n"); table.insert(sb, table_print (value, indent + 2, done)) table.insert(sb, string.rep (" ", indent)) -- indent it table.insert(sb, "}\n"); elseif "number" == type(key) then table.insert(sb, string.format("\"%s\"\n", tostring(value))) else table.insert(sb, string.format( "%s = \"%s\"\n", tostring (key), tostring(value))) end end return table.concat(sb) else return tt .. "\n" end end function to_string( tbl ) if "nil" == type( tbl ) then return tostring(nil) elseif "table" == type( tbl ) then return table_print(tbl) elseif "string" == type( tbl ) then return tbl else tostring(tbl) end end
Example
print(to_string{ "Lua",user="Mariacher", {{co=coroutine.create(function() end),{number=12345.6789}}, func=function() end}, boolt=true} )
This prints
"Lua" { { { number = "12345.6789" } co = "thread: 0212B848" } func = "function: 01FC7C70" } boolt = "true" user = "Mariacher"
See Also: LuaRecipes - Recursive table print/serialization
-- Count the number of times a value occurs in a table function table_count(tt, item) local count count = 0 for ii,xx in pairs(tt) do if item == xx then count = count + 1 end end return count end
-- Remove duplicates from a table array (doesn't currently work -- on key-value tables) function table_unique(tt) local newtable newtable = {} for ii,xx in ipairs(tt) do if(table_count(newtable, xx) == 0) then newtable[#newtable+1] = xx end end return newtable end
RandomSample has a better algorithm but it has the same issue with math.random
-- Careful of random number seeding here- you will need to randomly -- seed before calling this function randomlist(l, samp) local newlist newlist = {} if not samp then samp = 0 else samp = #l - samp end while #l > samp do local idx idx = math.random(1, #l) newlist[#newlist + 1] = l[idx] table.remove(l, idx) end return newlist end
ISSUE: Users should use built-in fn table.concat(table,divider)
-- implode(separator, table) function implode(d,p) local newstr newstr = "" if(#p == 1) then return p[1] end for ii = 1, (#p-1) do newstr = newstr .. p[ii] .. d end newstr = newstr .. p[#p] return newstr end
-- explode(seperator, string) function explode(d,p) local t, ll t={} ll=0 if(#p == 1) then return p end while true do l=string.find(p,d,ll+1,true) -- find the next d in the string if l~=nil then -- if "not not" found then.. table.insert(t, string.sub(p,ll,l-1)) -- Save it in our array. ll=l+1 -- save just after where we found it for searching next time. else table.insert(t, string.sub(p,ll)) -- Save what's left in our array. break -- Break at end, as it should be, according to the lua manual. end end return t end
-- combo({a,b,c},2) ==> a,b a,c b,c -- an iterating solution would be appreciated too function combo(lst, n) local a, number, select, newlist newlist = {} number = #lst select = n a = {} for i=1,select do a[#a+1] = i end newthing = {} while(1) do local newrow = {} for i = 1,select do newrow[#newrow + 1] = lst[a[i]] end newlist[#newlist + 1] = newrow i=select while(a[i] == (number - select + i)) do i = i - 1 end if(i < 1) then break end a[i] = a[i] + 1 for j=i, select do a[j] = a[i] + j - i end end return newlist end
By RichardWarburton.
function combo(t,n) local n,max,tn,output=n,#t,{},{} for x=1,n do tn[x],output[x]=x,t[x] end -- Generate 1st combo tn[n]=tn[n]-1 -- Needed to output 1st combo return function() -- Iterator fn local t,tn,output,x,n,max=t,tn,output,n,n,max while tn[x]==max+x-n do x=x-1 end -- Locate update point if x==0 then return nil end -- Return if no update point tn[x]=tn[x]+1 -- Add 1 to update point (UP) output[x]=t[tn[x]] -- Update output at UP for i=x+1,n do tn[i]=tn[i-1]+1 -- Update points to right of UP output[i]=t[tn[i]] -- Update output to refect change in points end return output end end