This is my custom function:
function scope(tbl, depth)
if (depth > 0) then
for k, v in pairs(tbl) do
if (type(v) ~= "table") then
print(v)
else
scope(v, depth - 1)
end
end
end
end
This is the usage: let
stuff = {
fruit = {
yellow = {
"Banana"
}, -- depth = 3
red = {
"Apple"
} -- depth = 3
},
city = {
"Toronto"
}, -- depth = 2
name = {
"Claudia"
} -- depth = 2
}
scope(stuff, 2) returns
Toronto
Claudia
Otherwise, scope(stuff, 3) returns
Banana
Apple
Toronto
Claudia
Advice on how to improve it? Maybe insert some code that displays nil if, as here, I specify depth value of 1 or a number greater than 3 (the depth of the table).
Related
How would I go about compiling values from a table using a string?
i.e.
NumberDef = {
[1] = 1,
[2] = 2,
[3] = 3
}
TextDef = {
["a"] = 1,
["b"] = 2,
["c"] = 3
}
If I was for example to request "1ABC3", how would I get it to output 1 1 2 3 3?
Greatly appreciate any response.
Try this:
s="1ABC3z9"
t=s:gsub(".",function (x)
local y=tonumber(x)
if y~=nil then
y=NumberDef[y]
else
y=TextDef[x:lower()]
end
return (y or x).." "
end)
print(t)
This may be simplified if you combine the two tables into one.
You can access values in a lua array like so:
TableName["IndexNameOrNumber"]
Using your example:
NumberDef = {
[1] = 1,
[2] = 2,
[3] = 3
}
TextDef = {
["a"] = 1,
["b"] = 2,
["c"] = 3
}
print(NumberDef[2])--Will print 2
print(TextDef["c"])--will print 3
If you wish to access all values of a Lua array you can loop through all values like so (similarly to a foreach in c#):
for i,v in next, TextDef do
print(i, v)
end
--Output:
--c 3
--a 1
--b 2
So to answer your request, you would request those values like so:
print(NumberDef[1], TextDef["a"], TextDef["b"], TextDef["c"], NumberDef[3])--Will print 1 1 2 3 3
One more point, if you're interested in concatenating lua string this can be accomplished like so:
string1 = string2 .. string3
Example:
local StringValue1 = "I"
local StringValue2 = "Love"
local StringValue3 = StringValue1 .. " " .. StringValue2 .. " Memes!"
print(StringValue3) -- Will print "I Love Memes!"
UPDATE
I whipped up a quick example code you could use to handle what you're looking for. This will go through the inputted string and check each of the two tables if the value you requested exists. If it does it will add it onto a string value and print at the end the final product.
local StringInput = "1abc3" -- Your request to find
local CombineString = "" --To combine the request
NumberDef = {
[1] = 1,
[2] = 2,
[3] = 3
}
TextDef = {
["a"] = 1,
["b"] = 2,
["c"] = 3
}
for i=1, #StringInput do --Foreach character in the string inputted do this
local CurrentCharacter = StringInput:sub(i,i); --get the current character from the loop position
local Num = tonumber(CurrentCharacter)--If possible convert to number
if TextDef[CurrentCharacter] then--if it exists in text def array then combine it
CombineString = CombineString .. TextDef[CurrentCharacter]
end
if NumberDef[Num] then --if it exists in number def array then combine it
CombineString = CombineString .. NumberDef[Num]
end
end
print("Combined: ", CombineString) --print the final product.
I am not sure yet what the problem is, I am trying to go through a ResizeArray and matching the item with the data type, and depending on this, take away the value in a specific field (iSpace) from thespace(which is how much space the inventory has), before returning the final value.
A snippet of my code :
let spaceleft =
let mutable count = 0 //used to store the index to get item from array
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count //creates an error
while count < inventory.Count do
let item = inventory.[count]
match item with
|Weapon weapon ->
thespace <- (thespace - weapon.iSpace)
|Bomb bomb ->
thespace <-(thespace - bomb.iSpace)
|Potion pot ->
thespace <- (thespace - pot.iSpace)
|Armour arm ->
thespace <- (thespace - arm.iSpace)
count <- count+1
thespace
I get an error about Int32, that has to do with the
printf "Count: %i \n" inventory.Count
line
Another problem is that thespace doesn't seem to change, and always returns as 60, although I have checked and inventory is not empty, it always has at least two items, 1 weapon and 1 armour, so thespace should atleast decrease yet it never does.
Other snippets that may help:
let inventory = ResizeArray[]
let initialise =
let mutable listr = roominit
let mutable curroom = 3
let mutable dead = false
inventory.Add(Weapon weap1)
inventory.Add(Armour a1)
let spacetogo = spaceleft //returns 60, although it should not
Also, apart from the iniitialise function, other functions seem not to be able to add items to the inventory properly, eg:
let ok, input = Int32.TryParse(Console.ReadLine())
match ok with
|false ->
printf "The weapon was left here \n"
complete <- false
|true ->
if input = 1 && spaceleft>= a.iSpace then
inventory.Add(Weapon a)
printf "\n %s added to the inventory \n" a.name
complete <- true
else
printf "\n The weapon was left here \n"
complete <- false
complete
You have spaceLeft as a constant value. To make it a function you need to add unit () as a parameter. Here's that change including a modification to make it much simpler (I've included my dummy types):
type X = { iSpace : int }
type Item = Weapon of X | Bomb of X | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let spaceleft () =
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count
for item in inventory do
let itemSpace =
match item with
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace
thespace <- thespace - itemSpace
thespace
spaceleft () // 55
The above code is quite imperative. If you want to make it more functional (and simpler still) you can use Seq.sumBy:
let spaceleft_functional () =
printf "Count: %i \n" inventory.Count
let spaceUsed =
inventory
|> Seq.sumBy (function
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace)
60 - spaceUsed
Just adding to the accepted answer: you can also match against record labels, as long as your inner types are records. Combine with an intrinsic type extension on the outer DU:
type X = { iSpace : int }
type Y = { iSpace : int }
type Item = Weapon of X | Bomb of Y | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let itemSpace = function
| Weapon { iSpace = s } | Bomb { iSpace = s }
| Potion { iSpace = s } | Armour { iSpace = s } -> s
type Item with static member (+) (a, b) = a + itemSpace b
60 - (Seq.fold (+) 0 inventory)
// val it : int = 55
Otherwise, you could resort to member constraint invocation expressions.
let inline space (x : ^t) = (^t : (member iSpace : int) (x))
I have an input file with the below content
child, parent, val
1 , 0 , a
2 , 1 , b
3 , 1 , c
4 , 2 , d
5 , 2 , e
I need to store them in an array named data_array by directly reading from the file without the header. Something like this
BEGIN {
while (getline < "input")
{
split($0,ft,",");
child=ft[1];
parent=ft[2];
value=ft[3];
#need help here in assigning two values into the array
data_array[child]=parent,value;
}
close("input");
}
The result_array holds the parent to child relationship with ordering.
result_array[parent]="all children separated by comma"
For example, parent 0 has one child called 1. Parent 1 has two children called 2, and 3.
The order of 2 and 3 are determined by alphabetically sorting the corresponding values.
Since the sorting of values results in b followed by c the array element should have 2,3.
There could be any number of children.
Childless nodes must be written with blank content.
These results must go into the final array in the following format.
Need help on this part to convert the data_array into the result_array
result_array["0"] = "1"
result_array["1"] = "2,3"
result_array["2"] = "4,5"
result_array["3"] = ""
result_array["4"] = ""
result_array["5"] = ""
Please shout if this is unclear.
With GNU awk for true multi-dimensional arrays and sorted_in:
$ cat tst.awk
BEGIN { FS=" *, *" }
NR==1 { for (i=1;i<=NF;i++) f[$i]=i; next }
{ parentsChildren2Vals[$(f["parent"])][$(f["child"])] = $(f["val"]) }
END {
for (parent in parentsChildren2Vals) {
PROCINFO["sorted_in"] = "#val_str_asc"
for (child in parentsChildren2Vals[parent]) {
parents2children[parent] = (parent in parents2children ?
parents2children[parent] "," : "") child
children[child]
}
}
for (child in children) {
parents2children[child]
}
PROCINFO["sorted_in"] = "#ind_num_asc"
for (parent in parents2children) {
printf "parents2children[\"%s\"] = \"%s\"\n", parent, parents2children[parent]
}
}
$ awk -f tst.awk file
parents2children["0"] = "1"
parents2children["1"] = "2,3"
parents2children["2"] = "4,5"
parents2children["3"] = ""
parents2children["4"] = ""
parents2children["5"] = ""
Situation:
table = { this, that, something else, x_coord, y_coord }
table.x_coord = { 1,2,3,4,7,8,n}
table.y_coord = { 2,4,5,9,n} -- numbers aren't fix
table.check_boxes = { [12] = a function,
[14] = a function,
[15] = a function,
[24] = a function,
[29] = a function,
....(n) }
As you can see, the x/y_coords forming check_boxes. For example:
table.x_coord[1]..table.y_coord[1] ~ table.check_boxes[1]
I use this to move the cursor in the Terminal between the check_boxes.
The problem now is in my cursormovement.
Currently I got a function that's searching for the next x/y_coord to the left/right/up/down depending on the given input (arrow-keys).
With return/space I call the function behind the checkbox.
Now, that could set the Cursor on positions where no check_boxes are given. Actually that's not a big deal, because when input == space/return, an inputhandler calls the function at
table.check_boxes[table.x_coorx[x_index]..table.y_coords[y_index]]
So if the cursor doesn't point on a function, just nothing happens.
But now I want the cursor to be forced to the next check_box. What can I do?
My Idea so far:
following function either for x or y, depending on input left/right up/down:
while true do
for k, v in pairs(table.check_boxes) do
if(table.x_coord[x_index] .. table.y_coord[y_index] == k then break end
end -- break -> okay, coord is at a checkbox
x_index = x_index + 1 -- or -1
if table.x_coord[x_index] == nil then
x_index = 1
end
end
The Problem now is that the last if will not allow cases like x_coord = {1,3} because it will set x_index to 1 if 2 is reached.
Any tips?
Edit:
Now I got that one going:
function cursorTioNextBoxRight()
searc_index = x_index
search = true
while search do
search_index = search_index + 1
if search_index > #table.x_coord then
search_index = 1
end
for k, v in pairs(table.check_boxes) do
if tonumber(table.x_coord[search_index..table.y_coord[y_index] == k then
x_index = search_index -- YAAAY
search = false
break
end
end
end
I'ts damn slow.
local x_newIndex = x_index + 1 --[[ or -1 --]]
x_index = table.x_coord[x_newIndex] and x_newIndex or x_index
x_index becomes x_newIndex when x_newIndex exists in the table otherwise it stays the old x_index
function cursorTioNextBoxRight()
searc_index = x_index
search = true
while search do
search_index = search_index + 1
if search_index > #table.x_coord then
search_index = 1
end
for k, v in pairs(table.check_boxes) do
if tonumber(table.x_coord[search_index..table.y_coord[y_index] == k then
x_index = search_index -- YAAAY
search = false
break
end
end
end
I will try to as concise as possible with my issue.
Firstly, files are:
block.lua
base.lua
main.lua
In block.lua I create a block, add collision detection and a cleanup code.
In base.lua I create a base made up of 4 columns and 10 rows. 40 blocks in total.
In main.lua I create 4 bases made from the base.class.
All is working fine once the game begins.
I remove the bases and call them again on level 2.
They create themselves ok BUT
when the enemy is destroyed once again, and the bases are to be rebuilt, I get an:
array index 1 is beyond array bounds:1..1
-- all the way up to--
array index 800 is beyond array bounds:1..159
it will then create the bases and continue until the enemys are destroyed and do the same again starting at :
array index 800 is beyond array bounds:1..159
-- all the way up to--
array index 4000 is beyond array bounds:1..159
The terminal points me at block.lua line 23
blockGroup:insert(blockNum,self.block)
Now I cant see anything wrong in the class, I have looked and googled for hours but all to no avail.
I would really appreciate a helping hand to guide me here please.
I have tried rewriting the "cleanup" etc but no joy.
I left a few commented out bits in there and removed some of the irrelevant stuff.
I post below the relevant code:
--MAIN.LUA--
function gameOver()
Runtime:removeEventListener("enterFrame", onEnterFrame)
Runtime:removeEventListener("enterFrame", movePlayer)
layers:removeSelf()
layers = nil
enemyCount = 0
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
allEnemys=nil
cleanupBlocks()
end
----------------------------------------------------------------------
-- LEVEL UP --
----------------------------------------------------------------------
function levelUp(level)
enemyCount = 0
local enemys = require("modules.enemy")
if allEnemys ~= nil then
for i = 1,#allEnemys do
timer.cancel(allEnemys[i].clock)
Runtime:removeEventListener( "enterFrame", allEnemys[i] )
display.remove(allEnemys[i].image)
allEnemys[i].image=nil
end
end
allEnemys=nil
cleanupBlocks()
levels()
end
----------------------------------------------------------------------
-- LEVELS --
----------------------------------------------------------------------
function levels(level)
function createInvader(x, y, row)
for j = 1, 2 do
for i = 1, 2 do
if allEnemys == nil then
allEnemys = {}
else
enemysCount=#allEnemys
end
allEnemys[#allEnemys + 1] = enemys:new()
allEnemys[#allEnemys ]:init(i * 60, j * 70 + 70,j)
allEnemys[#allEnemys ]:start()
end
end
end
createInvader()
--[[function createBases1()
local base = require("modules.base")
for i = 1, 4 do
base:new()
base:init(i * 180 - 130, 850)
end
end ]]--
createBases()
end
--BLOCK.LUA--
local block = {}
local block_mt = { __index = block}
local scene = scene
local blockGroup = display.newGroup()
local blockNum = 0
function block:new() -- constructor
local group = {}
return setmetatable( group, block_mt )
end
function block:init(xloc,yloc) --initializer
-- Create attributes
self.block = display.newRect( xloc,yloc,10,10)
self.block:setFillColor ( 2, 255, 14 )
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
local blockCollisionFilter = { categoryBits = 128, maskBits = 387}
physics.addBody( self.block, "static", {filter = blockCollisionFilter})
self.count = 1
end
function cleanupBlocks()
--[[ print(blockNum, blockGroup.numChildren)
for i=1,blockGroup.numChildren do
blockGroup[1]:removeSelf()
blockGroup[1] = nil
end ]]--
print(blockNum, blockGroup.numChildren)
while blockGroup.numChildren>0 do
display.remove(blockGroup[1])
blockGroup[1]=nil
end
end
function block:start()
--- Create Listeneres
self.block:addEventListener( "collision", self )
scene:addEventListener('base_block_event', self)
end
return block
--BASE.LUA--
local base = {}
local base_mt = { __index = base}
local scene = scene
local block = require("modules.block")
function base:new() -- constructor
local group = {}
return setmetatable( group, base_mt )
end
function base:init(xloc, yloc) --initializer
-- Create attributes
local base
for j = 1, 4 do
for i = 1, 10 do
base = block:new()
base:init(xloc+i * 10,yloc+j * 10)
base:start()
end
end
end
return base
I see you use
blockNum = blockNum + 1
blockGroup:insert(blockNum,self.block)
Try to use
blockGroup:insert(self.block)
just to see if you still get that error.