recursive array loop?

BlitzMax Forums/BlitzMax Beginners Area/recursive array loop?

kimgar(Posted 2007) [#1]
hi,
i am trying to make a recursive function that loops through a multidimensional array, i've found this PHP code
Function  loop($array,  $parent=''){ 
 
     foreach(  $array  as  $option  =>  $value  ){ 
         If(  $parent  !=  ''  ){ 
             $option  =  $parent  .  '['  .  $option  .  ']'; 
         } 
         If(  is_array($value)  ){ 
             loop($value,  $option); 
         }  Else  { 
             ?> 
     <div><?php  echo  $option;  ?>  =  <?php  echo  $value;  ?></div> 
             <?php 
         } 
     } 

 } 

loop  (  $names  );


i am still learning the blitzmax syntax and do not know php very well, so i am struggling with porting the php idea to blitzmax...is it even possible? or is the array handling in blitzmax too different?


ImaginaryHuman(Posted 2007) [#2]
Why do you need recursion? Don't you know how many dimensiosn your array has, so you can just use nested for-next loops?


Perturbatio(Posted 2007) [#3]
A problem I can see is that BMax requires you to know the type of array, the arrays in PHP can hold variable values.

You *could* do it with objects I suppose, but I've no doubt there'll be problems doing it.


Czar Flavius(Posted 2007) [#4]
"or is the array handling in blitzmax too different?"

Short answer: yes. If you describe exactly what it is you're trying to do, there might be alternative methods.


kimgar(Posted 2007) [#5]
in short, what i am trying to achieve is to copy a xml structure to a treeview, and use the treeview to draw objects from attributes in the xml.


kimgar(Posted 2007) [#6]
i got it working, but the code is nasty, i was thinking that if i could nail that recursive loop, i'd learn some ways of array handling that would clean up my code a bit...

my code at the moment populating a level 5 array:
TL.level[levelCnt].obj[objCnt].subObj1[subObj1Cnt].subObj2[subObj2Cnt].xObj = TL.level[levelCnt].obj[objCnt].subObj1[subObj1Cnt].subObj2[subObj2Cnt].xObj[..xObjCnt+1]
TL.level[levelCnt].obj[objCnt].subObj1[subObj1Cnt].subObj2[subObj2Cnt].xObj[xObjCnt] = node


...please let me know if anyone has any alternative methods?


QuietBloke(Posted 2007) [#7]
funny enough Im doing something similar.

Im not at my home PC right now so its from memory but in a nutshell I have all my data in a TMap

a TMap has two parameters so the key is the field name and the value is the value stored as a string value OR another TMap.

In the procedure to read the TMap

Procedure processData(inData:TMap)

it cycles through the keys in inData.

For readkey:string = eachin inData.keys

You can then see if the value if the key is another TMap.

If TMap(getvaluefromkey(inData,readkey)) Then
' Call myself passing the TMap value
processData(TMap(getvaluefromkey(inData,readkey)))
Else
print inkey + " = " + String(getvaluefromkey(inData,readkey)

The actual code syntax is probably all wrong Im working from memory but thats roughly it.

When I get time I was going to change it to just use some sort of TList as a stack so instead of recursive calling I push/pop my state using the stack.


kimgar(Posted 2007) [#8]
ah, the TMap returns. i had a feeling it would.
Thanks for the TMap info, i think i get where you are going.

will read up on hashtables and see if can understand better the difference between TLists and TMaps...


kimgar(Posted 2007) [#9]
umm, ok, if i can assume that a TMap works like a hash table, TMaps sounds like a better idea than TLists as they like arrays, use a direct lookup thereby being faster.

is this correct, or am i completely off the rail here?


ziggy(Posted 2007) [#10]
I think It is much more efficient to implement complex tree structures (like xml structures) using your own object design. something like:
Type MyNode
    Field Childs:TList = New TList
    Method AddChild(Node:MyNode)
        if node <> null then
            childs.addlast(Node)
        else
            throw "Null nodes are not allowed"
        endif
    End Method
End Type

Local Root:MyNode = New MyNode


You can get all the nodes in the root. You can get any subnode of any node. the same as a tree control. Obviously you may have to implement the CountNodes, GetNodeAtIndex, RemoveNode, etc... but it should be very easy.


kimgar(Posted 2007) [#11]
mmhm, that is not too far from what i've got already...
so many ways to achieve this - don't know which one to go for...

my newbie head is also thinking of a single TList/TMap of types with parentID fields, so that i could retrieve data with matching parentID? sounds like an easy, but maybe not very efficient way....
for local node:myNode = eachin nodelist
    if (node.parentID = 20)
        print node.name
    endif
next



ziggy(Posted 2007) [#12]
You will have to deal with some 'seek Id' 'comapre ID' etc for every node. why don't you think of nodes as real objects? I mean, store any child node in its parent node.

you can do:
Type MyNode
    Field Childs:TList = New TList
    Field Name:String
    Method AddNode:MyNode(Node:MyNode)
        if node <> null then
            childs.addlast(Node)
            return Node
        else
            throw "Null nodes are not allowed"
        endif
    End Method
    Method CountNodes:int()
        return Childs.Count()
    End Method
    Method NodeAtIndex:MyNode(index:int)
         return childs.valueAtIndex(index)
    End Method
End Type

'Create the root node:
Local Root:MyNode = New MyNode

'Create tree nodes in the root:
Local AuxNode:MyNode 
AuxNode = New MyNode
AuxNode.Name = "First Child Node"
Root.AddNode(AuxNode)

AuxNode = New MyNode
AuxNode.Name = "Second Child Node"
Root.AddNode(AuxNode)

AuxNode = New MyNode
AuxNode.Name = "Third Child Node"
Root.AddNode(AuxNode)

'Now we add a subnode to the second node in the root.
AuxNode = root.NodeAtIndex(1)  'We get the second node of the root (the first one is index 0)
AuxNode.AddNode(New MyNode)  'We add it a child node
AuxNode.NodeAtIndex(0).Name = "This is a subnode!"  'We set the child node a name


this is a very fast and flexible way to create a complex tree.

I haven't tested it, becouse I'm not at my computer now, so it can be buggy.


ziggy(Posted 2007) [#13]
I have a better example, it also produces recursive execution.

This example generates a little cross-referencing issue, so be sure to call RemoveNode if you need to delete a node from its parent childs list. If you don't do this, the object will remain in memory, ignored by the GC


kimgar(Posted 2007) [#14]
putting a addNode method in the type, seems like a good idea - i think that will clean up my code a lot.

and now if i can find a clever way to jump backwards as my recursive leafs are dying i think i am all set.
maybe if i keep the level history in a array or something, i'll be able to jump from an outer leaf all the way back to root, hmmm


kimgar(Posted 2007) [#15]
ah, beautiful ziggy! i just saw your last post - recursive execution, that sounds like exactly what i need!

thanks a lot ziggy, i have to rush off now, but i will have a look at your code in the morning, and see what i can make out of it - it looks very promising, thanks!