From c13e7586d803aa0727be8d25f5c62d044e5e2f63 Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Mon, 9 Apr 2018 22:11:03 -0700 Subject: [PATCH] use Damerau-Levenshtein distance Former-commit-id: 073f2be728690d9ef8662bb9960b91424694d12d [formerly 073f2be728690d9ef8662bb9960b91424694d12d [formerly f9f4e84e4d4b771b0eb9d7a9965bf8d7d246e91a [formerly c913a0221468ea66309d376cd7aa6e5ee94eefbe]]] Former-commit-id: b65b58d2e287b62da016134632cd51281d4fafc3 Former-commit-id: a33c88925474e837abe5061fbd4a7930879f7230 [formerly 2905c2ed4801d650acd6f94261c553a33f2cfc80] Former-commit-id: 5a892a6304228629f31bd7f10040f1b2150d5ddb --- README.md | 4 +-- cointop/search.go | 2 +- pkg/levenshtein/levenshtein.go | 57 +++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index db7184a..a56ac9a 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,8 @@ Key|Action Space|Alias to enter key Ctrl+c|Alias to quit Ctrl+d|Jump page down (vim style) -Ctrl+n|Go to next page (vim style) -Ctrl+p|Go to previous page (vim style) +Ctrl+n|Go to next page +Ctrl+p|Go to previous page Ctrl+r|Force refresh Ctrl+u|Jump page up (vim style) Alt+|Sort current column in ascending order diff --git a/cointop/search.go b/cointop/search.go index 56bbe47..b83fcc5 100644 --- a/cointop/search.go +++ b/cointop/search.go @@ -59,7 +59,7 @@ func (ct *Cointop) search(q string) error { return nil } // store index with the smallest levenshtein - dist := levenshtein.Distance(name, q) + dist := levenshtein.DamerauLevenshteinDistance(name, q) if min == -1 || dist <= min { idx = i min = dist diff --git a/pkg/levenshtein/levenshtein.go b/pkg/levenshtein/levenshtein.go index 9c6e3ac..4355748 100644 --- a/pkg/levenshtein/levenshtein.go +++ b/pkg/levenshtein/levenshtein.go @@ -1,5 +1,10 @@ package levenshtein +import ( + "math" + "strings" +) + // Distance Levenshtein distance // The Levenshtein distance between two strings is defined as the minimum // number of edits needed to transform one string into the other, with the @@ -43,15 +48,51 @@ func Distance(str1, str2 string) int { return column[lenS1] } -func min(a, b, c int) int { - if a < b { - if a < c { - return a +// DamerauLevenshteinDistance calculates the damerau-levenshtein distance between s1 and s2. +// Reference: [Damerau-Levenshtein Distance](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance) +// Note that this calculation's result isn't normalized. (not between 0 and 1.) +// and if s1 and s2 are exactly the same, the result is 0. +func DamerauLevenshteinDistance(s1, s2 string) int { + if s1 == s2 { + return 0 + } + s1Array := strings.Split(s1, "") + s2Array := strings.Split(s2, "") + lenS1Array := len(s1Array) + lenS2Array := len(s2Array) + m := make([][]int, lenS1Array+1) + var cost int + for i := range m { + m[i] = make([]int, lenS2Array+1) + } + for i := 0; i < lenS1Array+1; i++ { + for j := 0; j < lenS2Array+1; j++ { + if i == 0 { + m[i][j] = j + } else if j == 0 { + m[i][j] = i + } else { + cost = 0 + if s1Array[i-1] != s2Array[j-1] { + cost = 1 + } + m[i][j] = min(m[i-1][j]+1, m[i][j-1]+1, m[i-1][j-1]+cost) + if i > 1 && j > 1 && s1Array[i-1] == s2Array[j-2] && s1Array[i-2] == s2Array[j-1] { + m[i][j] = min(m[i][j], m[i-2][j-2]+cost) + } + } } - } else { - if b < c { - return b + } + return m[lenS1Array][lenS2Array] +} + +// min returns the minimum number of passed int slices. +func min(is ...int) int { + min := int(math.MaxInt64) + for _, v := range is { + if min > v { + min = v } } - return c + return min }