Solved

VBSript recursion in function

Posted on 2013-12-23
12
366 Views
Last Modified: 2013-12-27
Experts, if possible can I get a little nudge on a recursion item within vbscript?

I have a function that I need to call on itself to cycle through some data.

Without overloading anyone with too much info, I basically have a dictionary object, that is laid out like so:

Dictionary Key = Parent Object
Dictionary Value = Children, each separated by "\\"


arrNavChildren = fncGatherNavChildren(strNavKey, dicRelationshipParentToChild.Item(strNavKey))

Function fncGatherNavChildren(strNavKey, strNavItem)
   If dicRelationshipParentToChild.Exists(strNavKey) Then
      fncGatherNavChildren = Split(strNavItem, "\\")
   Else
      fncGatherNavChildren = ""
   End If
End Function

Open in new window


Basically, I need to see about having the function call itself on each pass, to see if there are more children to add to the array.  *If that makes sense.



So, it could be like this:

ParentA, ChildA\\ChildB\\ChildC
ChildB, SubChildA\\SubChildB...  and so on.

Would somebody happen to know where I can find information on how to accomplish this?  The Google Zhar hasn't been too helpful as of yet.
0
Comment
Question by:usslindstrom
  • 6
  • 4
  • 2
12 Comments
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39736459
Are you sure you have your data set up correctly?  

Beer = rating
key("Heady Topper")="4.7"
key("Pliny The Younger")="4.65"
key("Zombie Dust")="4.61"

Are you saying you want to look up "Zombie Dust", find the rating of 4.61, then find all other beers that have 4.61 rating?
0
 
LVL 5

Author Comment

by:usslindstrom
ID: 39736501
Yeah - basically.  I know it sounds weird - but let me see if I can elaborate.

In the structure I posted above, let's expand it and add more data:


ParentA, ChildA\\ChildB\\ChildC
ParentB, ChildD\\ChildE\\ChildF
ParentC, ChildG
ParentD, ChildH\\ChildI

So, using this method, it's easy for me to grab any of these "parents" child objects.  But, the Child objects can also be parents in my data structure...

ChildA, *NO_CHILDREN*
ChildB, SubChildA\\SubChildB
ChildC, SubChildC\\SubChildD\\SubChildE
ChildD, *NO_CHILDREN*
ChildE, *NO_CHILDREN*
ChildF, SubChildF

And this process could repeat itself indefinately...

SubChildA, *NO_CHILDREN*
SubChildB, SubSubChildA\\SubSubChildB
etc.


In a tree view, the above data would be layed out like so:
    ParentA
        ChildA
        ChildB
            SubChildA
            SubChildB
                SubSubChildA
                SubSubChildB
        ChildC
            SubChildC
            SubChildD
            SubChildE
    ParentB
        ChildD
        ChildE
        ChildF
            SubChildF
    ParentC
        ChildG
    ParentD
        ChildH
        ChildI

*If this makes sense.
0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39736556
>And this process could repeat itself indefinitely...

and that gets you to an endless loop.  If that is the case, there is something wrong in how you set up your data.


Below assumes you have a dictionary object with key "ParentA" that contains "ChildA\\ChildB\\ChildC"

When you look up the key, "ParentA" it will convert the result item to a new array, then loop through and check to see if there are more children.  If so, it will add to the array

'ParentA, ChildA\\ChildB\\ChildC
'ParentB, ChildD\\ChildE\\ChildF
'ParentC, ChildG
'ParentD, ChildH\\ChildI

dim MyDictionary
Set MyDictionary=Server.CreateObject("Scripting.Dictionary")
MyDictionary.Add "ParentA","ChildA\\ChildB\\ChildC"
MyDictionary.Add "ParentB", "ChildD\\ChildE\\ChildF"
MyDictionary.Add "ParentC", "ChildG"
MyDictionary.Add "ParentD", "ChildH\\ChildI"

'create the holding variable
dim newString, temp
newString=""


dim strP="ParentA,ParentB,ParentC,ParentD"
arrP=split(strP,",")
for each parent in arrP  
temp=""
childtemp=""
   if MyDictionary.Exists(parent)= true then ' check to see if ParentA exists.
        temp=MyDictionary.item(parent)
        newString=newString&temp&","
        arrTemp=split(temp,"\\") 'create an array from ChildA\\ChildB\\ChildC"
        for each child in arrTemp
            if MyDictionary.Exists(child)= true then
                newString=newString&MyDictionary.item(child)&","
            end if
        next
   end if
next
' now we end up with a comma at the end of our string and we need to take it out
newString=left(newString,len(newString)-1)

Open in new window

If you think you need an endless loop, then we should look at your data structure because that does not sound right.
0
 
LVL 5

Author Comment

by:usslindstrom
ID: 39736590
Please bear with me, I'm going over everything you're trying to show me.  *Thanks for the assist btw.

- Looking at the  logic of your example, I'm reading into it, that it would only perform 2 levels of parent --> child relationship passes.

It would grab the dictionary defined "parent" node, and pass through, up to the "ChildX" ones, but nothing in the "subChildX" tree, because it wasn't coded in.

I was hoping there would just be a quick function that I could throw together, that would per-say allow me to have "ParentA" defined, then it run through the data and give me the tree output of every child object.  (i.e.  ParentA is defined in the dictionary, and has ChildA,B,&C., Child A also has children objects of E,D,&F)

ParentA
    ChildA
        SubChildE
        SubChildD
        SubChildF
    ChildB
    ChildC
etc.

I was thinking it could be a simple function that would basically return the data values I have.  Meaning, I query ParentA, it returns \\ChildA,B,&C.  Run through the array of the returned values, and check if any of them are parents as well.  Continue this cycle until there aren't any more matches.
0
 
LVL 52

Assisted Solution

by:Scott Fell, EE MVE
Scott Fell,  EE MVE earned 200 total points
ID: 39736795
This is untested.  The first run checks the parents and dedupes answers.   Then we keep looping until we don't get anymore answers.

'ParentA, ChildA\\ChildB\\ChildC
'ParentB, ChildD\\ChildE\\ChildF
'ParentC, ChildG
'ParentD, ChildH\\ChildI

dim MyDictionary
Set MyDictionary=Server.CreateObject("Scripting.Dictionary")
MyDictionary.Add "ParentA","ChildA\\ChildB\\ChildC"
MyDictionary.Add "ParentB", "ChildD\\ChildE\\ChildF"
MyDictionary.Add "ParentC", "ChildG"
MyDictionary.Add "ParentD", "ChildH\\ChildI"

'create the holding variable
dim newString, temp
newString=""


dim strP="ParentA,ParentB,ParentC,ParentD"
arrP=split(strP,",")
for each parent in arrP  
temp=""
childtemp=""
stop="no"
   if ItExists(parent)= True then ' check to see if ParentA exists.
        go="yes"
        temp=checkTemp(MyDictionary.item(parent),0)
         ' dedupe
        temp=dedupe(temp)
        do until go="no"
            newArray=split(temp,"\\")
            for each word in newArray
                temp=temp&"\\"&checkTemp(MyDictionary.item(word),UBound(newArray))
            next
            temp=dedupe(temp)
        loop
    final=left(temp,len(temp)-2) ' get rid of final \\    
   end if
next


function ItExists(e)
    ItExists=False
    if MyDictionary.Exists(e)= true then 
        ItExists=True
    end if
end function
function dedupe(d)
    dedupe=""
    'd=aaa\\bbb\ccc\\aaa\\eeee
    arrD=split(d,"\\")
    for each dTest in arrD
        if instr(dTest,dedupe)=0 then
            dedupe=dTest
        end if
    next
end function


function checkTemp(x,count)
    arrTemp=split(x,"\\") 'create an array from ChildA\\ChildB\\ChildC"
        for each child in arrTemp
            if MyDictionary.Exists(child)= true then
                checkTemp=checkTemp&MyDictionary.item(child)&"\\"
                else
                if count>0 then
                    go="no"
                end if
            end if
        next
        checkTemp=checkTemp&left(checkTemp,len(checkTemp)-2) 'get rid of last \\
end function

Open in new window

0
 
LVL 5

Author Comment

by:usslindstrom
ID: 39736834
Wow! - Thanks.  Give me a minute to read through what you're showing me, so I can understand it...
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 51

Expert Comment

by:Bill Prew
ID: 39737071
Can't resist taking a shot at this, but just coming up to speed.

Just curious, how do you populate the data? Any reason a delimiter string was used for the "array" of children? Rather than say an array, or another dictionary object (yes, you can nest objects).

~bp
0
 
LVL 52

Expert Comment

by:Scott Fell, EE MVE
ID: 39737090
It will be nice to see another version...
0
 
LVL 5

Author Comment

by:usslindstrom
ID: 39737188
It's data from AD.

I actually have 2 dictionary objects currently, and I've been trying to get it working with multiple attempts at storing the data.

I'm making a HTA template that rolls through AD and provides some lookups based on clicking an object.  I set the ID in the HTA to the DN of the object I just clicked, and so far it's great.  The original draft had me using two separate list boxes, which is all fine...  Except I wanted to convert it to using expansive and contracting unordered lists (<ul>) using a mix of js.

I've got it almost entirely worked out, but got hung up with what you guys are assisting me on.

//-----------------------------------

In my original build my structure was as follows:

DictionaryObject
Key = AD DN of object
Value = Re-hashed output of the tree path (I.E. DOMAIN\OU\OU\OU)

This method worked fairly well, as I could sort the dictionary based on the value, and it gave me a great ordered list.

My second attempt, is where I'm at right now.  I have two dictionary objects, one of the base tree that contains the root domains, and from there it branches out into filling in the 2nd dictionary.  I was adding the "\\" as I knew I could just split on those chars together, and I was under the idea that it would be easier than it is.

As you can tell, I may be tackling this wrong, and there's probably a better way to store the data.  And you bring up a good point BP, with the value of the dictionary object just being an array.

I'd imagine I'd still be where I'm at, with the need for a function to call itself.  I think I see where Padas was showing me to go, but I still don't quite get it yet.
0
 
LVL 51

Accepted Solution

by:
Bill Prew earned 300 total points
ID: 39737329
Okay, see what you think of this recursive approach:

' Constants
strEndNode = "*NO_CHILDREN*"

' Set up dictionary object
Set dicNodes = CreateObject("Scripting.Dictionary")
dicNodes.CompareMode = vbTextCompare
 
' Load some test data into the dictionary
dicNodes.Add "ParentA", "ChildA\\ChildB\\ChildC"
dicNodes.Add "ParentB", "ChildD\\ChildE\\ChildF"
dicNodes.Add "ParentC", "ChildG"
dicNodes.Add "ParentD", "ChildH\\ChildI"
dicNodes.Add "ChildA", strEndNode
dicNodes.Add "ChildB", "SubChildA\\SubChildB"
dicNodes.Add "ChildC", "SubChildC\\SubChildD\\SubChildE"
dicNodes.Add "ChildD", strEndNode
dicNodes.Add "ChildE", strEndNode
dicNodes.Add "ChildF", "SubChildF"
dicNodes.Add "SubChildA", strEndNode
dicNodes.Add "SubChildB", "SubSubChildA\\SubSubChildB"
dicNodes.Add "SubSubChildA", strEndNode
dicNodes.Add "SubSubChildB", strEndNode
 
' Start recursive scan of the dictionary for a parent key
ScanDict "ParentA", 0
 
Function ScanDict(strKey, intIndent)
   ' Display this key in indented list
   Wscript.Echo String(intIndent, " ") & strKey
   ' If this key is in the dictionary, process it
   If dicNodes.Exists(strKey) Then
      strData = dicNodes.Item(strKey)
      ' See if it contains any child nodes
      If strData <> strEndNode Then
         ' Split the child node list, and recursively process each child
         For Each strChild in Split(strData, "\\")
            ScanDict strChild, intIndent + 2
         Next
      End If
   End If
End Function
 
' Wrap up
set dicNodes = Nothing

Open in new window

~bp
0
 
LVL 5

Author Closing Comment

by:usslindstrom
ID: 39742576
Sorry for the late reply here guys.  I've been knee deep in masaging the script to get it working correctly in my instance...

I ended up using BP's example (but thanks to both of you for supplying me a direction to start heading).  Ultimately, in order to pull it off in my environment, I ended up with a few dictionary objects:

1.  The nav tree that contains all items from AD
2.  A relationship that has one-->many (Parent --> Child)
3.  A relationship that has one-->one (Child --> Parent)
4.  A duplicate check (If .Exists) as it gets added to the HTML code
5.  BP's example, that I used to throw the navObject & subLevel (int = int +1 loop) to see where I was in the tree.

Using a mixture of ALL of the above dictionaries, I now have a working HTA that has a point-click navigation tree of AD.  Where you click on an OU, and all the sub OUs get added as nested <ul>'s to each node.  It's probably pretty sloppy - but it works.

Thanks for the nudge guys, you both make EE a great place to come back and collaborate on.
0
 
LVL 5

Author Comment

by:usslindstrom
ID: 39742593
Here's a copy, if anyone's interested.  *Ignore the layout, that'll come later.

I had to rename the following files in order to upload it to EE:

.hta --> .txt    
     .\AD_GUI.hta

.vbs --> .txt
     .\Scripts\AD\*.vbs
     .\Scripts\DataManip\*.vbs
     .\Scripts\Global\*.vbs
     .\Scripts\HTMLOutput\*.vbs
     .\Scripts\Init\*.vbs

.js --> .txt
     .\Scripts\CreateTree\*.js

.\Scripts\TxtAssist\TxtAssist.vbs --> TxtAssist.txt
.\Scripts\TxtAssist\TxtAssist.cfg --> TxtAssist_cfg.txt
AD-GUI.zip
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now