Description

This example demonstrates how to implement a class name filter (aka class navigation), like the one you see in many Eclipse-based IDEs.

Usage Instructions

To open any class in the editor quickly, press ⌘O (Navigate | Class) and start typing the name of the class. Choose the class from a drop-down list that appears.

This diaglog allows you to quickly filter out classes based on the text you enter.

Your input string must begin with an upper case alpha (A-Z) letter.

The next letter may be upper or lower case.

If it is lower case, then all sequential lower case letters that you enter will match exactly to the lower case letters found in the class name.

If you enter an upper case letter, then it will find the next upper case letter (ignoring any lower case letters in between your previous match an the matching upper case letter.)





Design Goals

Make something that works

Make it so that there is little performance hit, no matter how many class names are added





Strategy

Use levels of maps of each letter in the alphabet that can be traversed to find the stored class names.

Sharding large sets of data is typically a good idea if you want to increase performance, but that works when different data sets can be separately loaded and processed and orchestrated back together.

Perhaps, just using a single map would have sufficed, but this was after all just a code example.

Maybe our next code example can run performance tests against this solution and a single map solution.

Cedar Tree

The tree brances (levels) are made of maps of maps, like a major branch with small branch off shoots to leaves/needles (classNames).... Something like this:





Golang Features

This golang code sample demonstrates the following go language features:

switch

struct

slice

map

pointers

range

substring

fmt





3rd Party Libraries

github.com/remogatto/prettytest

github.com/go-goodies/go_utils



Note that we preface github.com/go-goodies/go_utils with a "." which makes its functions directly accessible in our go program without prefacing it with any package name alias.

Now, we can reference go_utils functions like so: c = IndexOf(input[i:i+1], className, c+1)

Which, by the way, returns the index of the current input character input[i:i+1] found in the string, className, starting at the index of c+1.





Code Example

classname_filter.go

package class_filter // main import ( . "fmt" . "github.com/go-goodies/go_utils" ) var ( tree * Tree ) // Level is the node that contains the alpha map for each level // Each level contains words that match that level's levelNumber // The first letter of each entry in the alpha map matches that key, e.g. "Hi" is at level 2 at key "H" type Level struct { alpha map [ string ] map [ string ] string // a, b, ..z, A, B .. Z => HelloWorld, HiWorld, WordlHello, HelloWeirWorld levelNumber int nextLevel * Level } // Tree contains the pointer to the top of the tree of levels type Tree struct { top * Level } // The Top() method points to the top of the tree. (Only downward navigation is supported) func ( tree * Tree ) Top () * Level { return tree . top } // PopulateAlphas populates the alphas map (one per level) with one letter per ALPHABET func PopulateAlphas () ( map [ string ] map [ string ] string ) { alphas := make ( map [ string ] map [ string ] string ) var thisChar string for _ , c := range ALPHABET { thisChar = Sprintf ( "%c" , c ) alphas [ thisChar ] = make ( map [ string ] string ) } return alphas } // PrintAlpha only prints letters that store classNames func PrintAlpha ( alpha map [ string ] map [ string ] string , levelNumber int ) { var thisChar string for _ , c := range ALPHABET { thisChar = Sprintf ( "%c" , c ) if len ( alpha [ thisChar ]) > 0 { Printf ( "alpha[%s] (%d) : %v

" , thisChar , levelNumber , alpha [ thisChar ] ) } } } /* Example: alpha[H] (6) : map[HiWorld:HiWorld] alpha[H] (9) : map[HelloWorld:HelloWorld] alpha[W] (9) : map[WordlHello:WordlHello] alpha[H] (13) : map[HelloWeirWorld:HelloWeirWorld] */ // PrintTree prints the elements containing data for the alphas map, prefaced with (level_number) func PrintTree ( tree Tree ) { for level := tree . Top (); level != nil ; level = level . nextLevel { PrintAlpha ( level . alpha , level . levelNumber ) } } // PopulateTree stores each className in the tree at the level equal to the length at alpha[first_letter_of_classname] func PopulateTree ( classNames [] string ) ( * Tree ) { alphas := PopulateAlphas () tree := new ( Tree ) tree . top = & Level { DeepCopy ( alphas ).( map [ string ] map [ string ] string ), 0 , nil } // startPos with level0 alpha map ready thisLevel := tree . Top () var curLevelNumber int for _ , className := range classNames { thisLevel = tree . Top () curLevelNumber = 0 // loop thru each letter of className // - if this is the last letter, store the className on this level in alpha[first_letter_of_className] // - else if nextLevel is nil then create a new Level and point nextLevel to it for c := 0 ; c < len ( className ); c ++ { // thisLetter := Sprintf("%s", className[c:c+1]) if c == len ( className ) - 1 { // store className as key and as value thisLevel . alpha [ className [ 0 : 1 ]][ className ] = className } else { // must keep going, populate nextLevel and set levelNumber if nextLevel is nil curLevelNumber += 1 if thisLevel . nextLevel == nil { thisLevel . nextLevel = & Level { DeepCopy ( alphas ).( map [ string ] map [ string ] string ), curLevelNumber , nil } } thisLevel = thisLevel . nextLevel } //Printf("thisLevel: %v

", *thisLevel) } } return tree } // FindClassNames uses global tree func FindClassNames ( input string ) ([] string ) { // First (cap) letter must be on level0 var levelsFound [] int var classNames [] string ptr := tree . Top () ptr = ptr . nextLevel for level := tree . Top (); level != nil ; level = level . nextLevel { if len ( level . alpha [ input [ 0 : 1 ]]) > 0 { levelsFound = append ( levelsFound , level . levelNumber ) for k , _ := range level . alpha [ input [ 0 : 1 ]] { // className is the key (level.alpha[input[input[0:1]]: map[Hi:]) classNames = append ( classNames , k ) } } } // Printf("levelsFound for input[0:1] (%s): %v

", input[0:1],levelsFound) // Printf("classNames: %v

", classNames) if len ( input ) == 1 { return classNames } // Start with slice of classNames that match 1st letter, now on to 2nd letter...and whittle it down var passingClassNames [] string fail := false for _ , className := range classNames { // Iterate thru each letter of input (i is input iterator) for i := 1 ; i < len ( input ) && ! fail ; { // Move thru each letter of className (c is className iterator) for c := 1 ; i < len ( input ) && c < len ( className ) && ! fail ; { //Printf("*** input[i:i+1]: %s, className[c:c+1]: %s

", input[i:i+1], className[c:c+1]) if input [ i : i + 1 ] == className [ c : c + 1 ] { // happy path (matching characters) i += 1 c += 1 } else if ! IsLower ( input [ i : i + 1 ]) { // at upper case input character c = IndexOf ( input [ i : i + 1 ], className , c + 1 ) if c == NOT_FOUND_INDEX { //Println("c == NOT_FOUND_INDEX") fail = true } else { i += 1 c += 1 } } else { fail = true } } } if ! fail { passingClassNames = append ( passingClassNames , className )} fail = false } //classNames := []string{"HelloWorld", "HiWorld"} return passingClassNames } /* Helper functions */ func PrintClassNames ( classNames [] string ) { for _ , className := range classNames { Printf ( "%s

" , className ) } } func FindAndPrintClassNames ( input string ) { Printf ( "ClassNames found for input: %s

" , input ) foundClassNames := FindClassNames ( input ) PrintClassNames ( foundClassNames ) Println ( Dashes ( 50 )) } func mainSTOP () { // Insert ClassNames in tree structure classNames := [] string { "HelloWorld" , "HiWorld" , "WordlHello" , "HelloWeirWorld" } tree = PopulateTree ( classNames ) Println ( "TREE:" ) PrintTree ( * tree ) Println ( Dashes ( 50 )) FindAndPrintClassNames ( "HW" ) FindAndPrintClassNames ( "He" ) FindAndPrintClassNames ( "Hi" ) FindAndPrintClassNames ( "HWW" ) }





Test Code

classnamefiltertest.go

package class_filter import ( "testing" "github.com/remogatto/prettytest" . "github.com/go-goodies/go_utils" . "fmt" ) var ( classNames [] string // tree *Tree ) func init () { // Insert ClassNames in tree structure classNames = [] string { "HelloWorld" , "HiWorld" , "WordlHello" , "HelloWeirWorld" } tree = PopulateTree ( classNames ) } type mySuite struct { prettytest . Suite } func TestRunner ( t * testing . T ) { prettytest . Run ( t , new ( mySuite )) } /* // Insert ClassNames in tree structure classNames := []string{"HelloWorld", "HiWorld", "WordlHello", "HelloWeirWorld"} tree = PopulateTree(classNames) */ func ( s * mySuite ) TestPopulateTree () { for level := tree . Top (); level != nil ; level = level . nextLevel { //PrintAlpha(level.alpha, level.levelNumber) var thisChar string for _ , c := range ALPHABET { thisChar = Sprintf ( "%c" , c ) if len ( level . alpha [ thisChar ]) > 0 { //s.Error(Sprintf("***: level.alpha[%s]: %v, level.levelNumber: %d", thisChar, level.alpha[thisChar], level.levelNumber)) if level . alpha [ thisChar ][ "HelloWorld" ] == "HelloWorld" { s . Equal ( level . levelNumber , 9 ) } if level . alpha [ thisChar ][ "HiWorld" ] == "HiWorld" { s . Equal ( level . levelNumber , 6 ) } if level . alpha [ thisChar ][ "WordlHello" ] == "WordlHello" { s . Equal ( level . levelNumber , 9 ) } if level . alpha [ thisChar ][ "HelloWeirWorld" ] == "HelloWeirWorld" { s . Equal ( level . levelNumber , 13 ) } } } } } func ( s * mySuite ) TestClassNameFilter () { var thisIndex int var foundClassNames [] string foundClassNames = FindClassNames ( "HW" ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HiWorld" }) s . Equal ( thisIndex >= 0 , true ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HelloWorld" }) s . Equal ( thisIndex >= 0 , true ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HelloWeirWorld" }) s . Equal ( thisIndex >= 0 , true ) s . Equal ( len ( foundClassNames ), 3 ) foundClassNames = FindClassNames ( "He" ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HelloWorld" }) s . Equal ( thisIndex >= 0 , true ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HelloWeirWorld" }) s . Equal ( thisIndex >= 0 , true ) s . Equal ( len ( foundClassNames ), 2 ) foundClassNames = FindClassNames ( "Hi" ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HiWorld" }) s . Equal ( thisIndex >= 0 , true ) s . Equal ( len ( foundClassNames ), 1 ) foundClassNames = FindClassNames ( "HWW" ) thisIndex = IndexOfGeneric ( len ( foundClassNames ), func ( i int ) bool { return foundClassNames [ i ] == "HelloWeirWorld" }) s . Equal ( thisIndex >= 0 , true ) s . Equal ( len ( foundClassNames ), 1 ) } func ( s * mySuite ) TestRemoveItemsFromInvoice () { s . Pending () }





Test Results

Testing started at 5:22 PM ... === RUN TestRunner class_filter.mySuite: [32mOK[0m TestClassNameFilter (11 assertion(s)) [32mOK[0m TestPopulateTree (4 assertion(s)) [33mPE[0m TestRemoveItemsFromInvoice (0 assertion(s)) 3 tests, 2 passed, 0 failed, 0 expected failures, 1 pending, 0 with no assertions --- PASS: TestRunner (0.00 seconds) PASS ok bitbucket.org/l3x/class_filter 0.013s Process finished with exit code 0





Notes

The Data Structures

We use a tree structure, composed of linked Levels, composed of maps that map to the first letter of the class names:



Here are the structures we use:

// Level is the node that contains the alpha map for each level // Each level contains words that match that level's levelNumber // The first letter of each entry in the alpha map matches that key, e.g. "Hi" is at level 2 at key "H" type Level struct { alpha map [ string ] map [ string ] string levelNumber int nextLevel * Level } // Tree contains the pointer to the top of the tree of levels type Tree struct { top * Level } // The Top() method points to the top of the tree. // Only downward navigation is supported. func ( tree * Tree ) Top () * Level { return tree . top }





If you were to change the package name to main and rename the function mainSTOP to main, it would give a feel for how the classNames are stored in the tree and show a few examples of the filter in action:

TREE: alpha[H] (6) : map[HiWorld:HiWorld] alpha[H] (9) : map[HelloWorld:HelloWorld] alpha[W] (9) : map[WordlHello:WordlHello] alpha[H] (13) : map[HelloWeirWorld:HelloWeirWorld] -------------------------------------------------- ClassNames found for input: HW HiWorld HelloWorld HelloWeirWorld -------------------------------------------------- ClassNames found for input: He HelloWorld HelloWeirWorld -------------------------------------------------- ClassNames found for input: Hi HiWorld -------------------------------------------------- ClassNames found for input: HWW HelloWeirWorld --------------------------------------------------





A Look at the Tree

If you were to uncomment the Printf("thisLevel: %v

", *thisLevel) line in PopulateTree you can see where the class names are stored:

thisLevel: {map[Z:map[] k:map[] r:map[] x:map[] L:map[] Q:map[] U:map[] j:map[] q:map[] G:map[] c:map[] a:map[] H:map[] E:map[] o:map[] h:map[] v:map[] d:map[] M:map[] N:map[] u:map[] X:map[] e:map[] B:map[] J:map[] s:map[] l:map[] g:map[] P:map[] m:map[] b:map[] f:map[] A:map[] C:map[] z:map[] R:map[] S:map[] I:map[] w:map[] Y:map[] F:map[] D:map[] T:map[] K:map[] V:map[] p:map[] y:map[] n:map[] O:map[] W:map[] i:map[] t:map[]] 1 } thisLevel: {map[U:map[] D:map[] E:map[] i:map[] o:map[] X:map[] I:map[] e:map[] J:map[] M:map[] d:map[] y:map[] n:map[] T:map[] j:map[] x:map[] P:map[] R:map[] c:map[] w:map[] B:map[] H:map[] a:map[] h:map[] q:map[] K:map[] Q:map[] W:map[] N:map[] V:map[] s:map[] C:map[] A:map[] G:map[] g:map[] u:map[] F:map[] Y:map[] p:map[] f:map[] z:map[] v:map[] k:map[] O:map[] r:map[] m:map[] S:map[] L:map[] b:map[] t:map[] Z:map[] l:map[]] 2 } thisLevel: {map[Z:map[] f:map[] c:map[] m:map[] N:map[] a:map[] H:map[] Y:map[] l:map[] n:map[] O:map[] q:map[] M:map[] V:map[] D:map[] k:map[] R:map[] U:map[] s:map[] C:map[] x:map[] Q:map[] F:map[] r:map[] b:map[] X:map[] j:map[] P:map[] J:map[] L:map[] W:map[] i:map[] I:map[] g:map[] B:map[] o:map[] p:map[] A:map[] G:map[] S:map[] d:map[] t:map[] z:map[] T:map[] E:map[] h:map[] v:map[] K:map[] e:map[] w:map[] u:map[] y:map[]] 3 } thisLevel: {map[H:map[] u:map[] n:map[] T:map[] B:map[] W:map[] m:map[] U:map[] o:map[] d:map[] V:map[] Y:map[] X:map[] Z:map[] z:map[] L:map[] Q:map[] K:map[] G:map[] r:map[] g:map[] J:map[] p:map[] s:map[] v:map[] x:map[] O:map[] c:map[] M:map[] F:map[] w:map[] t:map[] a:map[] f:map[] C:map[] D:map[] e:map[] i:map[] j:map[] R:map[] E:map[] l:map[] q:map[] S:map[] b:map[] h:map[] A:map[] k:map[] P:map[] I:map[] N:map[] y:map[]] 4 } thisLevel: {map[H:map[] D:map[] T:map[] j:map[] r:map[] J:map[] d:map[] t:map[] K:map[] m:map[] L:map[] e:map[] o:map[] p:map[] h:map[] G:map[] S:map[] a:map[] U:map[] l:map[] c:map[] M:map[] u:map[] Y:map[] v:map[] x:map[] b:map[] V:map[] s:map[] n:map[] A:map[] R:map[] g:map[] B:map[] F:map[] w:map[] N:map[] C:map[] k:map[] O:map[] q:map[] W:map[] i:map[] E:map[] X:map[] Z:map[] f:map[] z:map[] P:map[] Q:map[] y:map[] I:map[]] 5 } thisLevel: {map[O:map[] N:map[] d:map[] U:map[] o:map[] l:map[] x:map[] c:map[] W:map[] H:map[] z:map[] T:map[] s:map[] v:map[] A:map[] Q:map[] t:map[] M:map[] f:map[] i:map[] r:map[] S:map[] I:map[] g:map[] e:map[] y:map[] E:map[] n:map[] a:map[] u:map[] p:map[] D:map[] L:map[] B:map[] b:map[] V:map[] h:map[] C:map[] R:map[] q:map[] J:map[] w:map[] Y:map[] Z:map[] P:map[] G:map[] K:map[] m:map[] F:map[] X:map[] j:map[] k:map[]] 6 } thisLevel: {map[E:map[] n:map[] N:map[] F:map[] Z:map[] x:map[] P:map[] m:map[] K:map[] S:map[] M:map[] o:map[] z:map[] T:map[] l:map[] q:map[] R:map[] J:map[] X:map[] h:map[] C:map[] k:map[] O:map[] u:map[] U:map[] Y:map[] f:map[] w:map[] b:map[] t:map[] p:map[] D:map[] v:map[] j:map[] G:map[] i:map[] Q:map[] r:map[] g:map[] H:map[] V:map[] a:map[] A:map[] c:map[] L:map[] d:map[] W:map[] y:map[] s:map[] I:map[] e:map[] B:map[]] 7 } thisLevel: {map[M:map[] H:map[] h:map[] z:map[] x:map[] c:map[] m:map[] d:map[] i:map[] B:map[] t:map[] N:map[] Y:map[] X:map[] v:map[] Q:map[] P:map[] r:map[] I:map[] A:map[] w:map[] b:map[] a:map[] u:map[] o:map[] p:map[] Z:map[] L:map[] G:map[] T:map[] j:map[] k:map[] O:map[] K:map[] U:map[] V:map[] y:map[] l:map[] q:map[] S:map[] J:map[] C:map[] f:map[] s:map[] R:map[] g:map[] E:map[] e:map[] F:map[] D:map[] n:map[] W:map[]] 8 } thisLevel: {map[D:map[] G:map[] J:map[] M:map[] p:map[] y:map[] v:map[] O:map[] c:map[] i:map[] W:map[] d:map[] H:map[] f:map[] j:map[] m:map[] w:map[] h:map[] k:map[] l:map[] n:map[] r:map[] x:map[] I:map[] N:map[] t:map[] u:map[] F:map[] Y:map[] s:map[] A:map[] T:map[] L:map[] Q:map[] a:map[] X:map[] R:map[] S:map[] g:map[] B:map[] b:map[] V:map[] C:map[] K:map[] e:map[] o:map[] E:map[] Z:map[] z:map[] P:map[] q:map[] U:map[]] 9 } thisLevel: {map[G:map[] J:map[] D:map[] p:map[] y:map[] v:map[] O:map[] c:map[] i:map[] M:map[] d:map[] H:map[HelloWorld:HelloWorld] f:map[] j:map[] m:map[] w:map[] W:map[] k:map[] l:map[] n:map[] r:map[] x:map[] I:map[] N:map[] h:map[] u:map[] F:map[] Y:map[] s:map[] A:map[] T:map[] L:map[] t:map[] a:map[] X:map[] R:map[] S:map[] g:map[] B:map[] Q:map[] V:map[] C:map[] K:map[] e:map[] b:map[] E:map[] Z:map[] z:map[] P:map[] q:map[] U:map[] o:map[]] 9 } thisLevel: {map[L:map[] Q:map[] U:map[] Z:map[] k:map[] r:map[] x:map[] a:map[] H:map[] E:map[] j:map[] q:map[] G:map[] c:map[] o:map[] h:map[] v:map[] X:map[] e:map[] B:map[] J:map[] d:map[] M:map[] N:map[] u:map[] s:map[] l:map[] g:map[] b:map[] f:map[] A:map[] P:map[] m:map[] I:map[] w:map[] Y:map[] F:map[] C:map[] z:map[] R:map[] S:map[] V:map[] p:map[] y:map[] D:map[] T:map[] K:map[] W:map[] i:map[] t:map[] n:map[] O:map[]] 1 0x2081f5740} thisLevel: {map[U:map[] D:map[] E:map[] i:map[] o:map[] X:map[] I:map[] T:map[] j:map[] e:map[] J:map[] M:map[] d:map[] y:map[] n:map[] x:map[] P:map[] R:map[] c:map[] K:map[] w:map[] B:map[] H:map[] a:map[] h:map[] q:map[] Q:map[] W:map[] N:map[] V:map[] s:map[] C:map[] A:map[] G:map[] g:map[] v:map[] k:map[] u:map[] F:map[] Y:map[] p:map[] f:map[] z:map[] O:map[] r:map[] m:map[] S:map[] L:map[] b:map[] t:map[] Z:map[] l:map[]] 2 0x208213820} thisLevel: {map[Y:map[] Z:map[] f:map[] c:map[] m:map[] N:map[] a:map[] H:map[] k:map[] l:map[] n:map[] O:map[] q:map[] M:map[] V:map[] D:map[] R:map[] x:map[] U:map[] s:map[] C:map[] Q:map[] F:map[] r:map[] i:map[] b:map[] X:map[] j:map[] P:map[] J:map[] L:map[] W:map[] I:map[] A:map[] g:map[] B:map[] o:map[] p:map[] T:map[] G:map[] S:map[] d:map[] t:map[] z:map[] y:map[] E:map[] h:map[] v:map[] K:map[] e:map[] w:map[] u:map[]] 3 0x208213f40} thisLevel: {map[B:map[] W:map[] H:map[] u:map[] n:map[] T:map[] U:map[] o:map[] m:map[] Z:map[] z:map[] L:map[] Q:map[] d:map[] V:map[] Y:map[] X:map[] K:map[] J:map[] p:map[] G:map[] r:map[] g:map[] c:map[] M:map[] F:map[] s:map[] v:map[] x:map[] O:map[] C:map[] D:map[] e:map[] i:map[] w:map[] t:map[] a:map[] f:map[] j:map[] R:map[] b:map[] h:map[] E:map[] l:map[] q:map[] S:map[] N:map[] y:map[] A:map[] k:map[] P:map[] I:map[]] 4 0x208200160} thisLevel: {map[D:map[] T:map[] j:map[] r:map[] J:map[] d:map[] H:map[] K:map[] m:map[] L:map[] e:map[] t:map[] p:map[] h:map[] G:map[] S:map[] a:map[] U:map[] o:map[] c:map[] M:map[] u:map[] l:map[] v:map[] x:map[] b:map[] V:map[] Y:map[] n:map[] A:map[] R:map[] g:map[] B:map[] F:map[] s:map[] N:map[] C:map[] k:map[] O:map[] q:map[] W:map[] i:map[] w:map[] X:map[] Z:map[] f:map[] z:map[] P:map[] Q:map[] y:map[] E:map[] I:map[]] 5 0x20821e240} thisLevel: {map[N:map[] d:map[] U:map[] o:map[] O:map[] c:map[] W:map[] H:map[] z:map[] T:map[] l:map[] x:map[] A:map[] Q:map[] t:map[] M:map[] f:map[] s:map[] v:map[] i:map[] r:map[] S:map[] I:map[] e:map[] y:map[] E:map[] n:map[] g:map[] p:map[] D:map[] L:map[] B:map[] b:map[] V:map[] a:map[] u:map[] h:map[] C:map[] R:map[] J:map[] w:map[] Y:map[] Z:map[] q:map[] K:map[] m:map[] F:map[] X:map[] j:map[] k:map[] P:map[] G:map[]] 6 0x20821e900} thisLevel: {map[O:map[] N:map[] d:map[] U:map[] o:map[] l:map[] x:map[] c:map[] W:map[] H:map[HiWorld:HiWorld] z:map[] T:map[] s:map[] v:map[] A:map[] Q:map[] t:map[] M:map[] f:map[] i:map[] r:map[] S:map[] I:map[] g:map[] e:map[] y:map[] E:map[] n:map[] a:map[] u:map[] p:map[] D:map[] L:map[] B:map[] b:map[] V:map[] h:map[] C:map[] R:map[] q:map[] J:map[] w:map[] Y:map[] Z:map[] P:map[] G:map[] K:map[] m:map[] F:map[] X:map[] j:map[] k:map[]] 6 0x20821e900} thisLevel: {map[L:map[] Q:map[] U:map[] Z:map[] k:map[] r:map[] x:map[] a:map[] H:map[] E:map[] j:map[] q:map[] G:map[] c:map[] o:map[] h:map[] v:map[] e:map[] B:map[] J:map[] d:map[] M:map[] N:map[] u:map[] X:map[] s:map[] l:map[] g:map[] b:map[] f:map[] A:map[] P:map[] m:map[] w:map[] Y:map[] F:map[] C:map[] z:map[] R:map[] S:map[] I:map[] V:map[] p:map[] y:map[] D:map[] T:map[] K:map[] W:map[] i:map[] t:map[] n:map[] O:map[]] 1 0x2081f5740} thisLevel: {map[U:map[] D:map[] E:map[] i:map[] o:map[] X:map[] I:map[] j:map[] e:map[] J:map[] M:map[] d:map[] y:map[] n:map[] T:map[] x:map[] P:map[] R:map[] c:map[] w:map[] B:map[] H:map[] a:map[] h:map[] q:map[] K:map[] Q:map[] W:map[] N:map[] V:map[] s:map[] C:map[] A:map[] G:map[] g:map[] k:map[] u:map[] F:map[] Y:map[] p:map[] f:map[] z:map[] v:map[] O:map[] r:map[] m:map[] S:map[] L:map[] b:map[] t:map[] Z:map[] l:map[]] 2 0x208213820} thisLevel: {map[a:map[] H:map[] Y:map[] Z:map[] f:map[] c:map[] m:map[] N:map[] V:map[] D:map[] k:map[] l:map[] n:map[] O:map[] q:map[] M:map[] R:map[] s:map[] C:map[] x:map[] U:map[] F:map[] r:map[] Q:map[] L:map[] W:map[] i:map[] b:map[] X:map[] j:map[] P:map[] J:map[] I:map[] o:map[] p:map[] A:map[] g:map[] B:map[] t:map[] z:map[] T:map[] G:map[] S:map[] d:map[] w:map[] u:map[] y:map[] E:map[] h:map[] v:map[] K:map[] e:map[]] 3 0x208213f40} thisLevel: {map[T:map[] B:map[] W:map[] H:map[] u:map[] n:map[] U:map[] o:map[] m:map[] X:map[] Z:map[] z:map[] L:map[] Q:map[] d:map[] V:map[] Y:map[] K:map[] J:map[] p:map[] G:map[] r:map[] g:map[] O:map[] c:map[] M:map[] F:map[] s:map[] v:map[] x:map[] f:map[] C:map[] D:map[] e:map[] i:map[] w:map[] t:map[] a:map[] j:map[] R:map[] S:map[] b:map[] h:map[] E:map[] l:map[] q:map[] I:map[] N:map[] y:map[] A:map[] k:map[] P:map[]] 4 0x208200160} thisLevel: {map[j:map[] r:map[] J:map[] d:map[] H:map[] D:map[] T:map[] L:map[] e:map[] t:map[] K:map[] m:map[] G:map[] S:map[] a:map[] U:map[] o:map[] p:map[] h:map[] M:map[] u:map[] l:map[] c:map[] b:map[] V:map[] Y:map[] v:map[] x:map[] R:map[] g:map[] B:map[] F:map[] s:map[] n:map[] A:map[] k:map[] O:map[] q:map[] W:map[] i:map[] w:map[] N:map[] C:map[] f:map[] z:map[] P:map[] Q:map[] y:map[] E:map[] X:map[] Z:map[] I:map[]] 5 0x20821e240} thisLevel: {map[N:map[] d:map[] U:map[] o:map[] O:map[] x:map[] c:map[] W:map[] H:map[HiWorld:HiWorld] z:map[] T:map[] l:map[] v:map[] A:map[] Q:map[] t:map[] M:map[] f:map[] s:map[] i:map[] r:map[] S:map[] I:map[] e:map[] y:map[] E:map[] n:map[] g:map[] u:map[] p:map[] D:map[] L:map[] B:map[] b:map[] V:map[] a:map[] h:map[] C:map[] R:map[] J:map[] w:map[] Y:map[] Z:map[] q:map[] G:map[] K:map[] m:map[] F:map[] X:map[] j:map[] k:map[] P:map[]] 6 0x20821e900} thisLevel: {map[N:map[] F:map[] E:map[] n:map[] m:map[] K:map[] S:map[] M:map[] o:map[] Z:map[] x:map[] P:map[] q:map[] R:map[] J:map[] X:map[] z:map[] T:map[] l:map[] O:map[] u:map[] U:map[] h:map[] C:map[] k:map[] w:map[] b:map[] Y:map[] f:map[] v:map[] j:map[] G:map[] i:map[] Q:map[] t:map[] p:map[] D:map[] r:map[] g:map[] A:map[] c:map[] L:map[] d:map[] H:map[] V:map[] a:map[] I:map[] e:map[] B:map[] W:map[] y:map[] s:map[]] 7 0x2082129c0} thisLevel: {map[x:map[] c:map[] m:map[] d:map[] M:map[] H:map[] h:map[] z:map[] Y:map[] X:map[] v:map[] Q:map[] i:map[] B:map[] t:map[] N:map[] A:map[] P:map[] r:map[] I:map[] o:map[] p:map[] Z:map[] L:map[] w:map[] b:map[] a:map[] u:map[] T:map[] G:map[] U:map[] j:map[] k:map[] O:map[] K:map[] S:map[] J:map[] V:map[] y:map[] l:map[] q:map[] C:map[] E:map[] f:map[] s:map[] R:map[] g:map[] W:map[] e:map[] F:map[] D:map[] n:map[]] 8 0x208200ae0} thisLevel: {map[J:map[] D:map[] G:map[] O:map[] c:map[] i:map[] M:map[] p:map[] y:map[] v:map[] j:map[] m:map[] w:map[] W:map[] d:map[] H:map[HelloWorld:HelloWorld] f:map[] r:map[] x:map[] I:map[] N:map[] h:map[] k:map[] l:map[] n:map[] s:map[] A:map[] T:map[] L:map[] t:map[] u:map[] F:map[] Y:map[] S:map[] g:map[] B:map[] Q:map[] a:map[] X:map[] R:map[] e:map[] b:map[] V:map[] C:map[] K:map[] P:map[] q:map[] U:map[] o:map[] E:map[] Z:map[] z:map[]] 9 } thisLevel: {map[G:map[] J:map[] D:map[] p:map[] y:map[] v:map[] O:map[] c:map[] i:map[] M:map[] d:map[] H:map[HelloWorld:HelloWorld] f:map[] j:map[] m:map[] w:map[] W:map[WordlHello:WordlHello] k:map[] l:map[] n:map[] r:map[] x:map[] I:map[] N:map[] h:map[] u:map[] F:map[] Y:map[] s:map[] A:map[] T:map[] L:map[] t:map[] a:map[] X:map[] R:map[] S:map[] g:map[] B:map[] Q:map[] V:map[] C:map[] K:map[] e:map[] b:map[] E:map[] Z:map[] z:map[] P:map[] q:map[] U:map[] o:map[]] 9 } thisLevel: {map[k:map[] r:map[] x:map[] L:map[] Q:map[] U:map[] Z:map[] q:map[] G:map[] c:map[] a:map[] H:map[] E:map[] j:map[] o:map[] h:map[] v:map[] M:map[] N:map[] u:map[] X:map[] e:map[] B:map[] J:map[] d:map[] s:map[] l:map[] g:map[] m:map[] b:map[] f:map[] A:map[] P:map[] z:map[] R:map[] S:map[] I:map[] w:map[] Y:map[] F:map[] C:map[] T:map[] K:map[] V:map[] p:map[] y:map[] D:map[] O:map[] W:map[] i:map[] t:map[] n:map[]] 1 0x2081f5740} thisLevel: {map[U:map[] D:map[] E:map[] i:map[] o:map[] X:map[] I:map[] j:map[] e:map[] J:map[] M:map[] d:map[] y:map[] n:map[] T:map[] x:map[] P:map[] R:map[] c:map[] w:map[] B:map[] H:map[] a:map[] h:map[] q:map[] K:map[] Q:map[] W:map[] N:map[] V:map[] s:map[] C:map[] A:map[] G:map[] g:map[] k:map[] u:map[] F:map[] Y:map[] p:map[] f:map[] z:map[] v:map[] O:map[] r:map[] m:map[] S:map[] L:map[] b:map[] t:map[] Z:map[] l:map[]] 2 0x208213820} thisLevel: {map[a:map[] H:map[] Y:map[] Z:map[] f:map[] c:map[] m:map[] N:map[] V:map[] D:map[] k:map[] l:map[] n:map[] O:map[] q:map[] M:map[] R:map[] s:map[] C:map[] x:map[] U:map[] F:map[] r:map[] Q:map[] L:map[] W:map[] i:map[] b:map[] X:map[] j:map[] P:map[] J:map[] I:map[] o:map[] p:map[] A:map[] g:map[] B:map[] t:map[] z:map[] T:map[] G:map[] S:map[] d:map[] w:map[] u:map[] y:map[] E:map[] h:map[] v:map[] K:map[] e:map[]] 3 0x208213f40} thisLevel: {map[T:map[] B:map[] W:map[] H:map[] u:map[] n:map[] U:map[] o:map[] m:map[] X:map[] Z:map[] z:map[] L:map[] Q:map[] d:map[] V:map[] Y:map[] K:map[] J:map[] p:map[] G:map[] r:map[] g:map[] O:map[] c:map[] M:map[] F:map[] s:map[] v:map[] x:map[] f:map[] C:map[] D:map[] e:map[] i:map[] w:map[] t:map[] a:map[] j:map[] R:map[] S:map[] b:map[] h:map[] E:map[] l:map[] q:map[] I:map[] N:map[] y:map[] A:map[] k:map[] P:map[]] 4 0x208200160} thisLevel: {map[H:map[] D:map[] T:map[] j:map[] r:map[] J:map[] d:map[] t:map[] K:map[] m:map[] L:map[] e:map[] o:map[] p:map[] h:map[] G:map[] S:map[] a:map[] U:map[] l:map[] c:map[] M:map[] u:map[] Y:map[] v:map[] x:map[] b:map[] V:map[] s:map[] n:map[] A:map[] R:map[] g:map[] B:map[] F:map[] w:map[] N:map[] C:map[] k:map[] O:map[] q:map[] W:map[] i:map[] E:map[] X:map[] Z:map[] f:map[] z:map[] P:map[] Q:map[] y:map[] I:map[]] 5 0x20821e240} thisLevel: {map[O:map[] N:map[] d:map[] U:map[] o:map[] l:map[] x:map[] c:map[] W:map[] H:map[HiWorld:HiWorld] z:map[] T:map[] s:map[] v:map[] A:map[] Q:map[] t:map[] M:map[] f:map[] i:map[] r:map[] S:map[] I:map[] g:map[] e:map[] y:map[] E:map[] n:map[] a:map[] u:map[] p:map[] D:map[] L:map[] B:map[] b:map[] V:map[] h:map[] C:map[] R:map[] q:map[] J:map[] w:map[] Y:map[] Z:map[] P:map[] G:map[] K:map[] m:map[] F:map[] X:map[] j:map[] k:map[]] 6 0x20821e900} thisLevel: {map[N:map[] F:map[] E:map[] n:map[] S:map[] M:map[] o:map[] Z:map[] x:map[] P:map[] m:map[] K:map[] J:map[] X:map[] z:map[] T:map[] l:map[] q:map[] R:map[] u:map[] U:map[] h:map[] C:map[] k:map[] O:map[] w:map[] b:map[] Y:map[] f:map[] G:map[] i:map[] Q:map[] t:map[] p:map[] D:map[] v:map[] j:map[] r:map[] g:map[] L:map[] d:map[] H:map[] V:map[] a:map[] A:map[] c:map[] e:map[] B:map[] W:map[] y:map[] s:map[] I:map[]] 7 0x2082129c0} thisLevel: {map[M:map[] H:map[] h:map[] z:map[] x:map[] c:map[] m:map[] d:map[] i:map[] B:map[] t:map[] N:map[] Y:map[] X:map[] v:map[] Q:map[] P:map[] r:map[] I:map[] A:map[] w:map[] b:map[] a:map[] u:map[] o:map[] p:map[] Z:map[] L:map[] G:map[] T:map[] j:map[] k:map[] O:map[] K:map[] U:map[] V:map[] y:map[] l:map[] q:map[] S:map[] J:map[] C:map[] f:map[] s:map[] R:map[] g:map[] E:map[] e:map[] F:map[] D:map[] n:map[] W:map[]] 8 0x208200ae0} thisLevel: {map[G:map[] J:map[] D:map[] p:map[] y:map[] v:map[] O:map[] c:map[] i:map[] M:map[] d:map[] H:map[HelloWorld:HelloWorld] f:map[] j:map[] m:map[] w:map[] W:map[WordlHello:WordlHello] k:map[] l:map[] n:map[] r:map[] x:map[] I:map[] N:map[] h:map[] u:map[] F:map[] Y:map[] s:map[] A:map[] T:map[] L:map[] t:map[] a:map[] X:map[] R:map[] S:map[] g:map[] B:map[] Q:map[] V:map[] C:map[] K:map[] e:map[] b:map[] E:map[] Z:map[] z:map[] P:map[] q:map[] U:map[] o:map[]] 9 } thisLevel: {map[i:map[] B:map[] M:map[] Y:map[] o:map[] x:map[] s:map[] c:map[] v:map[] I:map[] Q:map[] t:map[] V:map[] p:map[] F:map[] E:map[] m:map[] W:map[] y:map[] D:map[] X:map[] T:map[] O:map[] j:map[] G:map[] L:map[] H:map[] u:map[] l:map[] n:map[] A:map[] K:map[] J:map[] U:map[] r:map[] g:map[] R:map[] P:map[] e:map[] b:map[] a:map[] f:map[] C:map[] z:map[] q:map[] S:map[] w:map[] N:map[] d:map[] Z:map[] h:map[] k:map[]] 10 } thisLevel: {map[D:map[] X:map[] x:map[] w:map[] B:map[] W:map[] U:map[] o:map[] P:map[] q:map[] K:map[] M:map[] d:map[] F:map[] k:map[] l:map[] S:map[] N:map[] a:map[] j:map[] g:map[] R:map[] b:map[] t:map[] v:map[] T:map[] G:map[] Y:map[] C:map[] A:map[] e:map[] i:map[] J:map[] L:map[] V:map[] I:map[] c:map[] Q:map[] H:map[] s:map[] m:map[] u:map[] f:map[] z:map[] O:map[] r:map[] n:map[] y:map[] p:map[] h:map[] E:map[] Z:map[]] 11 } thisLevel: {map[W:map[] d:map[] M:map[] y:map[] I:map[] p:map[] f:map[] v:map[] A:map[] S:map[] J:map[] u:map[] h:map[] C:map[] H:map[] o:map[] L:map[] Q:map[] e:map[] w:map[] b:map[] t:map[] s:map[] x:map[] R:map[] c:map[] j:map[] i:map[] B:map[] Y:map[] F:map[] X:map[] z:map[] q:map[] O:map[] N:map[] V:map[] U:map[] E:map[] n:map[] T:map[] K:map[] Z:map[] l:map[] g:map[] m:map[] a:map[] D:map[] k:map[] P:map[] r:map[] G:map[]] 12 } thisLevel: {map[F:map[] U:map[] Y:map[] o:map[] h:map[] D:map[] Q:map[] a:map[] I:map[] S:map[] Z:map[] n:map[] M:map[] s:map[] p:map[] y:map[] z:map[] T:map[] O:map[] q:map[] W:map[] H:map[] r:map[] K:map[] A:map[] x:map[] g:map[] w:map[] V:map[] L:map[] k:map[] R:map[] i:map[] B:map[] E:map[] m:map[] c:map[] N:map[] C:map[] t:map[] u:map[] X:map[] f:map[] v:map[] j:map[] J:map[] b:map[] l:map[] P:map[] G:map[] e:map[] d:map[]] 13 } thisLevel: {map[Y:map[] o:map[] h:map[] D:map[] Q:map[] a:map[] F:map[] U:map[] Z:map[] n:map[] I:map[] S:map[] M:map[] s:map[] z:map[] T:map[] O:map[] q:map[] W:map[] H:map[HelloWeirWorld:HelloWeirWorld] p:map[] y:map[] r:map[] K:map[] g:map[] w:map[] V:map[] A:map[] x:map[] R:map[] i:map[] B:map[] L:map[] k:map[] c:map[] N:map[] C:map[] E:map[] m:map[] X:map[] f:map[] v:map[] j:map[] J:map[] b:map[] t:map[] u:map[] l:map[] P:map[] e:map[] d:map[] G:map[]] 13 }





A Better Way?

In this code example, the class names are stored in a tree with several levels of hash maps to hash maps.

There are no more levels than there are letters in the longest class name.

I tried to use maps as much as possible, but some slice element iteration and manipulation and linked node navigation also exists.

Can you think of a more efficient way to store/filter the class names?

If so, please share your thoughts.

Thanks! ~ Lex



References