9 Replies Latest reply on Apr 23, 2006 2:35 PM by BSterner

    Dynamic Nested Structs

    Neo Rye Level 1
      I'm looking for a way to build a dynamic nested structure in cfscript using a for loop. Something like:
      <cfset MyStruct = StructNew()>
      <cfset MyStruct["A"] = StructNew()>
      <cfset MyStruct["A"]["B"] = StructNew()>
      <cfset MyStruct["A"]["B"]["C"]= StructNew()>
      <cfset MyStruct["A"]["B"]["C"]["D"]= StructNew()>
      <cfset MyStruct["A"]["B"]["D"]["R"]= StructNew()>

      The depth of the nested structure is unknown, 2 to 1000 and the A, B, C, D, R are all unknown. I have no problem creating the first struct MyStruct["A"], but can't seem to add the second + nested struct to the first dynamically in my loop. Seems like I want to concatenate each nested structure to the previous structure as I go.

      Any thoughts?

      <cfdump var="#MyStruct#">
        • 1. Re: Dynamic Nested Structs
          Level 7
          Neo Rye wrote:
          > I'm looking for a way to build a dynamic nested structure in cfscript using a

          <cfscript>
          root=structNew();
          for (i=1; i LTE 10; i=i+1) {
          // or use some other naming scheme for the nested structs
          root["#i#"]=structNew();
          root["#i#"].a=i;
          root["#i#"].b=i*10;
          root["#i#"].c=i*100;
          }
          </cfscript>

          <cfdump var="#root#">
          • 2. Dynamic Nested Structs
            Neo Rye Level 1
            Not quite. Your's only creates one nested struct. Mine needs to be more like a nested tree.
            A
            B B
            C C C
            D D D D


            <cfscript>
            root=structNew();
            for (i=1; i LTE 10; i=i+1) {
            // or use some other naming scheme for the nested structs
            root["A"]=structNew();
            root["A"]["B']=structNew();
            root["A"]["B"]["C"]=structNew();
            ... and on and on. but without having to hard code it. What if I have 15 nested structs? It would look something like:
            root["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]["?"]=structNew( );
            ...and I'd have to create 15 individual structs leading up to it.

            }
            </cfscript>
            <cfdump var="#root#">

            Dump this and you'll see what I need it to look like:
            <cfset MyStruct = StructNew()>
            <cfset MyStruct["A"] = StructNew()>
            <cfset MyStruct["A"]["B"] = StructNew()>
            <cfset MyStruct["A"]["B"]["C"]= StructNew()>
            <cfset MyStruct["A"]["B"]["C"]["D"]= StructNew()>
            <cfset MyStruct["A"]["B"]["D"]["R"]= StructNew()>
            <cfdump var="#MyStruct#">
            • 3. Re: Dynamic Nested Structs
              Level 7
              Neo Rye wrote:
              > Not quite. Your's only creates one nested struct. Mine needs to be more like a
              > nested tree.

              you edited the post after i submitted, the ABCDR bits weren't in the entry i saw
              via the newsgroup. in any case, the structure below has only 1 root. is that the
              case? or i each row a separate structure?

              > A
              > B B
              > C C C
              > D D D D


              what determines the branches in your "tree"? use that to create the for loops.
              • 4. Re: Dynamic Nested Structs
                BSterner Level 1
                what determines the branches in your "tree"?

                eggsactly. Neo Rye, you can dynamically loop and create nested structures to your heart's delight. The question here is what determines the depth of each nested structure. Sounds like a recursive function may be the answer.

                Can you elaborate on how you're trying to create the "tree".
                • 5. Dynamic Nested Structs
                  Neo Rye Level 1
                  I'm trying to build a nested structure of all names in a database. I'd guess that I'll have 1 root called root, then probably A-Z nested structs within the root. Then A-Z structs in all the first level A-Z structs and so on, this would probably go 50 deep.

                  The keys would be A-Z if there was a matching name with a letter at that position, probably not a lot of Z's as the second letter of someones name, so we would skip Z's at that level.

                  So now if you're name started with D, you would start at the struct root["D"]. Now root["D"] is our root so to speak, but now we are looking for the second letter in your name "A", so we would be at root["D"]["A"] ... so in the end I'd be at root["D"]["A"]["V"]["E"].

                  Now when I got to root["D"]["A"]["V"] of the struct, I'd also see all the other variations from there, ie root["D"]["A"]["V"]["I"]["D"]
                  • 6. Re: Dynamic Nested Structs
                    BSterner Level 1
                    Hmm...interesting, uh, task. Anyways, is something like this what you're after. One thing to note, I added a "endOfName" flag, to indicate if there was a name "Dan" and "Daniel" or "Fred" and "Fredrick".
                    • 7. Re: Dynamic Nested Structs
                      Neo Rye Level 1
                      That's beautiful! So simple and clean. I would have never gotten that, something about recursion that makes my brain go blank.

                      Now I can finish my Ajax Google type "suggest" for my database. I was told that this is similar to how Google probably stores the data for their "suggest" tool. It should be supper fast and efficient as compared to storing it some other way or querying the database.

                      We have a search field to search on things like firstname, lastname, email , phone etc. I'll load all that info into a struct within my applications memory and then when some types say "DAV" in the search field, I can return my "auto-complete" suggestions.

                      Something like:
                      if(StructKeyExists(root["D"]["A"],"V")){
                      //convert remaining top [n] keys to an array of strings and return to client, giving priority to weighted structs.
                      }

                      Then every time someone selects say DAVE for the auto-complete, I can increment the value of the root["D"]["A"]["V"]["E"] = IncrementValue(root["D"]["A"]["V"]["E"] ), giving it more weight in my suggestions and moving it to the top of the suggestions.

                      That's the concept anyway and you sure have helped me get so much closer.

                      Thanks!
                      • 8. Re: Dynamic Nested Structs
                        BSterner Level 1
                        Just as an fyi, there's obviously lots of variations on how you could write this. If you didn't want to pass the name (Since it's not changing with each recursive call for a particular name in the list) and/or pos with each function call, you could set these in the first for loop as global variables and have it increment 'pos' inside your function (before the recursive call). Really depends on how it's being implemented and how you plan on interfacing with it.

                        • 9. Re: Dynamic Nested Structs
                          BSterner Level 1
                          One last thing. To avoid redundant traversal of your structure for duplicate names, you may want to do a SELECT DISTINCT in your original query, or, if you need every individual record, do a QoQ, just select the name and use this for building your structure. Depending on the number of duplicates and length of the names, the overhead associated with doing an extra query may or may not save you execution time.

                          Most likely, it will.