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\n", 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\n", *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\n", input[0:1],levelsFound)
// Printf("classNames: %v\n", 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\n", 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\n", className)
}
}
func FindAndPrintClassNames(input string) {
Printf("ClassNames found for input: %s\n", 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\n", *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