Skip to content

Commit 0bd9efe

Browse files
committed
Replace the Levenshtein sort with indexOf
1 parent 7460c18 commit 0bd9efe

File tree

2 files changed

+8
-46
lines changed

2 files changed

+8
-46
lines changed

stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/query/filter/DefaultUserQueryFilter.kt

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ import io.getstream.chat.android.ui.common.feature.messages.composer.query.forma
2424
import io.getstream.chat.android.ui.common.feature.messages.composer.transliteration.DefaultStreamTransliterator
2525
import io.getstream.chat.android.ui.common.feature.messages.composer.transliteration.StreamTransliterator
2626
import io.getstream.log.taggedLogger
27-
import kotlin.math.min
2827

2928
/**
3029
* Default [QueryFilter] for [User] objects used in mention suggestions.
3130
*
3231
* Keeps only users whose normalized name (or id) contains the normalized query as a substring,
33-
* then sorts results by Levenshtein distance so the closest matches appear first. Normalization
34-
* applies lowercasing, diacritics removal, and optional transliteration.
32+
* then sorts results by match position so prefix matches appear first. Normalization applies
33+
* lowercasing, diacritics removal, and optional transliteration.
3534
*
3635
* @param transliterator The transliterator to use for normalizing strings.
3736
*/
@@ -54,47 +53,10 @@ public class DefaultUserQueryFilter(
5453
return items
5554
.mapNotNull { user ->
5655
val formattedName = queryFormatter.format(query = user.name.ifBlank(user::id))
57-
if (formattedName.contains(formattedQuery)) {
58-
user to levenshteinDistance(formattedQuery, formattedName)
59-
} else {
60-
null
61-
}
56+
val index = formattedName.indexOf(formattedQuery)
57+
if (index >= 0) user to index else null
6258
}
63-
.sortedBy { (_, distance) -> distance }
59+
.sortedBy { (_, index) -> index }
6460
.map { (user, _) -> user }
6561
}
66-
67-
private fun levenshteinDistance(search: String, target: String): Int {
68-
when {
69-
search == target -> return 0
70-
search.isEmpty() -> return target.length
71-
target.isEmpty() -> return search.length
72-
}
73-
74-
val searchLength = search.length + 1
75-
val targetLength = target.length + 1
76-
77-
var cost = Array(searchLength) { it }
78-
var newCost = Array(searchLength) { 0 }
79-
80-
for (i in 1 until targetLength) {
81-
newCost[0] = i
82-
83-
for (j in 1 until searchLength) {
84-
val match = if (search[j - 1] == target[i - 1]) 0 else 1
85-
86-
val costReplace = cost[j - 1] + match
87-
val costInsert = cost[j] + 1
88-
val costDelete = newCost[j - 1] + 1
89-
90-
newCost[j] = min(min(costInsert, costDelete), costReplace)
91-
}
92-
93-
val swap = cost
94-
cost = newCost
95-
newCost = swap
96-
}
97-
98-
return cost[searchLength - 1]
99-
}
10062
}

stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/query/filter/DefaultUserQueryFilterTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ internal class DefaultUserQueryFilterTest {
7474
}
7575

7676
@Test
77-
fun `results are sorted by levenshtein distance`() {
78-
val users = listOf(user("Charlie Alice"), user("Alice"), user("Bob Alice Smith"))
77+
fun `results are sorted by match position`() {
78+
val users = listOf(user("Johann"), user("Anne"), user("Marianne"))
7979

80-
assertEquals(listOf("Alice", "Charlie Alice", "Bob Alice Smith"), filter.filter(users, "alice").names())
80+
assertEquals(listOf("Anne", "Johann", "Marianne"), filter.filter(users, "ann").names())
8181
}
8282

8383
@Test

0 commit comments

Comments
 (0)