code simplification

improved unit tests
This commit is contained in:
2019-12-14 13:13:36 +00:00
parent d6727ddad1
commit 38b5416752
2 changed files with 124 additions and 53 deletions

View File

@@ -102,46 +102,39 @@ interface ILevTrie : ICharTrie<IntArray> {
fun fuzzySearch(word : String, maxResult: Int) : List<Pair<String, Int>> { fun fuzzySearch(word : String, maxResult: Int) : List<Pair<String, Int>> {
val result = sortedSetOf<Pair<String, Int>>(compareBy({ it.second }, { it.first })) val result = sortedSetOf<Pair<String, Int>>(compareBy({ it.second }, { it.first }))
val requiredSize = word.length + 1 val requiredSize = word.length + 1
fun visitNode(stack: List<StackContext<LevNode, Unit>>) : TreeNodeVisitor.VisitOutcome { val visitor = object: TreeNodeVisitor<LevNode, Unit> {
if(stack.size > 1) { override fun visitPre(stack: List<StackContext<LevNode, Unit>>): TreeNodeVisitor.VisitOutcome {
val currentStackElement = stack.last() val currentStackElement = stack.last()
if(currentStackElement.node.key == null) { val currentNode = currentStackElement.node
val sb = StringBuilder() if(currentNode.payload == null ||
for(c in currentStackElement.node.linealDescendant()) { currentNode.payload!!.size < requiredSize) {
sb.append(c)
}
val candidate = sb.toString()
val distance = stack[stack.size - 2].node.payload!![word.length]
result.add(candidate to distance)
if(result.size > maxResult) {
result.remove(result.last())
}
return TreeNodeVisitor.VisitOutcome.SKIP
} else {
return distanceCalculator.compute(keyChecker, stack, word,
if(result.size == maxResult) result.last().second else -1)
}
} else {
return TreeNodeVisitor.VisitOutcome.CONTINUE
}
}
val visitor = if(root.payload == null || root.payload!!.size < requiredSize) {
object: TreeNodeVisitor<LevNode, Unit> {
override fun visitPre(stack: List<StackContext<LevNode, Unit>>): TreeNodeVisitor.VisitOutcome {
val currentNode = stack.last()
if(stack.size == 1) { if(stack.size == 1) {
currentNode.node.payload = IntArray(requiredSize) { i -> i } currentNode.payload = IntArray(requiredSize) { i -> i }
} else { } else {
currentNode.node.payload = IntArray(requiredSize) { i -> if(i == 0) stack.size - 1 else 0 } currentNode.payload = IntArray(requiredSize) { i -> if(i == 0) stack.size - 1 else 0 }
} }
visitNode(stack) }
if(stack.size > 1) {
if(currentStackElement.node.key == null) {
val sb = StringBuilder()
for(c in currentStackElement.node.linealDescendant()) {
sb.append(c)
}
val candidate = sb.toString()
val distance = stack[stack.size - 2].node.payload!![word.length]
result.add(candidate to distance)
if(result.size > maxResult) {
result.remove(result.last())
}
return TreeNodeVisitor.VisitOutcome.SKIP
} else {
return distanceCalculator.compute(keyChecker, stack, word,
if(result.size == maxResult) result.last().second else -1)
}
} else {
return TreeNodeVisitor.VisitOutcome.CONTINUE return TreeNodeVisitor.VisitOutcome.CONTINUE
} }
} }
} else object: TreeNodeVisitor<LevNode, Unit> {
override fun visitPre(stack: List<StackContext<LevNode, Unit>>): TreeNodeVisitor.VisitOutcome {
return visitNode(stack)
}
} }
val walker = TreeWalker<LevNode, Unit>(visitor) val walker = TreeWalker<LevNode, Unit>(visitor)
walker.walk(root) walker.walk(root)

View File

@@ -1,33 +1,111 @@
package net.woggioni.klevtree package net.woggioni.klevtree
import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.io.BufferedReader
import java.io.InputStreamReader
class LevtreeTest { class LevtreeTest {
@Test @Test
fun foo() { fun trivialTest() {
val reader = BufferedReader(
InputStreamReader(javaClass.getResourceAsStream("/cracklib-small")))
val tree = LevTrie() val tree = LevTrie()
tree.caseSensitive = false tree.caseSensitive = false
try {
for(line in reader.lines()) {
tree.add(line.asIterable())
}
} finally {
reader.close()
}
println(tree.add("dailies"))
var node = tree.search("dailies")
println(node!!.linealDescendant())
tree.remove("dailies")
node = tree.search("dailies")
println(node)
tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN
val result = tree.fuzzySearch("daiiles", 5) val word = "dailies"
println(result) run {
val pair = tree.add(word)
Assert.assertTrue(pair.first)
val node = tree.search(word)
Assert.assertNotNull(node)
Assert.assertEquals(
word,
node!!.linealDescendant().fold(StringBuilder(), StringBuilder::append).toString()
)
val result = tree.fuzzySearch(word, 5)
Assert.assertEquals(1, result.size)
Assert.assertEquals(word to 0, result[0])
}
run {
tree.remove(word)
val node = tree.search(word)
Assert.assertNull(node)
val result = tree.fuzzySearch(word, 5)
Assert.assertEquals(0, result.size)
}
}
private fun initLevTrie() : LevTrie {
val words = listOf(
"tired",
"authorise",
"exercise",
"bloody",
"ritual",
"trail",
"resort",
"landowner",
"navy",
"captivate",
"captivity",
"north")
return run {
val res = LevTrie()
words.forEach {res.add(it)}
res
}
}
@Test
fun levenshteinDistanceTest() {
val tree = initLevTrie()
tree.caseSensitive = false
tree.algorithm = ILevTrie.Algorithm.LEVENSHTEIN
run {
val word = "fired"
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("tired" to 1, result[0])
}
run {
val word = "tierd"
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("tired" to 2, result[0])
}
run {
val word = "tierd"
tree.remove("tired")
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("trail" to 4, result[0])
}
}
@Test
fun damerauLevenshteinDistanceTest() {
val tree = initLevTrie()
tree.caseSensitive = false
tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN
run {
val word = "fired"
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("tired" to 1, result[0])
}
run {
val word = "capitvate"
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("captivate" to 1, result[0])
Assert.assertEquals("captivity" to 3, result[1])
}
run {
tree.remove("captivate")
val word = "capitvate"
val result = tree.fuzzySearch(word, 4)
Assert.assertEquals(4, result.size)
Assert.assertEquals("captivity" to 3, result[0])
}
} }
} }