A few days ago I talked about a rarely used function called structSort. Today I'm going to talk about a related set of functions, structFindValue and structFindKey.
As you can imagine, these two functions will search a structure for either a particular value, or a particular key. Here is a simple example of structFindValue:
<cfscript>
s = structNew();
s["Jacob"] = structNew();
s["Jacob"].gender = "male";
s["Jacob"].age = "3";
s["Lynn"] = structNew();
s["Lynn"].gender = "female";
s["Lynn"].age = "2";
s["Noah"] = structNew();
s["Noah"].gender = "male";
s["Noah"].age = "1";
males = structFindValue(s,"male","all");
writeOutput("There are #arraylen(males)# male children.");
</cfscript>
We define a simple structure, s, then a set of children under it. Then we use the structFindValue function to search the structure. We pass it "male" as the value to look for, and "all" to make it return all matches. The result is an array of matches. Each element of the array contains three keys: The key where the value matched. The "owner", which is a pointer to the parent structure of the key. Lastly, it returns path, which is the specific path from the root structure to the key matched. structFindKey pretty much works the same way, except that "value" is returned instead of key, and obviously value is the value of the matched key.
So, obviously these functions would be useful to search complex structures. If you have any questions, please post them in the comments field.
Archived Comments
Hi Ray,
I am currently creating a nested structure in the form of a tree so I can add and remove nodes dynamically. structfindkey seems to be the thing to figure out which node i want to add to and all is well thus far.
But I can't for the life of me figure out how to use the path string returned in the array from structFindKey. I want to insert a new node structure at this point but can't figure out the syntax required to use the path string.
So far I have come up with something along the lines of:
<cfset aNode = structfindkey(stTree,url.node)>
<cfif not arrayisempty(aNode)>
<cfset temp = createuuid()>
<cfset "stTree#aNode[1].path#.children[temp]"=structnew()>
</cfif>
This fails saying that stTree.517C30E2E000BA099A8EF6851B588090.children[518BD777-E000-BA09-9A2BC429BD67D23A]
is not a valid variable name
stTree.517C30E2E000BA099A8EF6851B588090.children has already been created as the root of my tree and the root of my structure.
Any ideas would be greatfully accepted.
As ever managed to answer my own question:
StructGet is the key, pass in the path you get from structKeyFind and it will return you a pointer to the bit of the structure you are looking for.
Not obvious that these things are returning pointers to the original structure somethimes
Is it possible to easily combine structFindValue and structFindKey?
For example, take this struct
name|bob
hair|brown
name|steve
hair|red
name|bill
hair|black
name|red
hair|black
For this case, if you used structFindValue(struct, "red) it would return both a reference to the person red, and steve's hair color!
Is there a way to combine StructFindvalue efficiently with StructFindKey() so we could say find red, but only for the key of hair?
Not that I know of - but don't forget that the path is returned for the results of structFindValue, so you can filter on the paths the match what you want.