Golang Code Examples

Filter Class Names

16 Sep 2014

Description

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

pta

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:

Cedar Tree



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:

    OK TestClassNameFilter           (11 assertion(s))
    OK TestPopulateTree              (4 assertion(s))
    PE 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


References

comments powered by Disqus
The content of this site is licensed under the Creative Commons 3.0License and code is licensed under a BSD license