英文:
How to sort list of strings that contains numbers and special characters in Kotlin
问题
I can provide the translated code part without any additional content:
val list = mutableListOf("FOO1", "FOO2", "7foo", "FOO8", "foo5", "foo27_QA", "foo4_1", "foo29_QA", "foo5_1", "foo4")
val sorted2 = list.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it }))
Please let me know if you need any further assistance.
英文:
I'm trying to sort list of strings in this order:
("7foo", "FOO1", "FOO2", "foo4", "foo4_1", "foo5", "foo5_1", "FOO8",
"Foo27_QA", "Foo29_QA")
I tried to use list.sortedWith{}
:
val list = mutableListOf("FOO1", "FOO2", "7foo", "FOO8", "foo5","foo27_QA", "foo4_1", "foo29_QA", "foo5_1", "foo4")
val sorted2 = list.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it }))
but the result is:
[7foo, FOO1, FOO2, Foo27_QA, Foo29_QA, foo4, foo4_1, foo5, foo5_1, FOO8]
答案1
得分: 2
以下是翻译好的部分:
"Default comparator, as well as CASE_INSENSITIVE_ORDER
comparator, follows lexicographic order. But, your expected result is not in such an order."
"在默认比较器和 CASE_INSENSITIVE_ORDER
比较器中,都是按照词典顺序进行排序。但是,您期望的结果不是按这种顺序排列的。"
"In lexicographic-case-insensitive order: Foo29_QA
is before foo4
. So the result is fine while using the default comparator."
"按照字典顺序且不区分大小写:Foo29_QA
在 foo4
之前。因此,在使用默认比较器时,结果是正确的。"
"So, you need to write your own comparator to apply your own logic."
"因此,您需要编写自己的比较器来应用自己的逻辑。"
"Okey, so how to sort your list (this won't be an easy-peasy task)."
"好的,那么如何对您的列表进行排序(这不会是一项容易的任务)。"
"I assume that your orders follows the pattern:"
"我假设您的排序遵循以下模式:"
">{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}
"
">{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}
"
"And we would like to sort it by:"
"并且我们想按以下方式对其进行排序:"
-
$number_prefix
DESC -
$number
ASC -
$alphanumeric_suffix
DESC -
$number_prefix
降序 -
$number
升序 -
$alphanumeric_suffix
降序
"So, finally, we can use something like:"
"因此,最终,我们可以使用类似以下方式:"
// create helper class for comparing
// 为比较创建辅助类
data class Element(
val originalValue: String,
val numberPrefix: Int?,
val number: Int?,
val suffix: String
)
// parse string into Element (for strings that not follow pattern
// `{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}`
// this may throw an exception
// 将字符串解析为 Element(适用于不符合模式 `{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}` 的字符串,这可能会引发异常)
fun parse(s: String): Element {
val normalized = s.lowercase()
val fooSplit = normalized.split("foo")
// determine numberPrefix
// 确定 numberPrefix
val numberPrefix = fooSplit.first().toIntOrNull()
// parse the rest
// 解析其余部分
val suffixRest = fooSplit.last()
val suffixRestSplit = suffixRest.split("_")
// and get rest of the data
// 获取其余数据
val number = suffixRestSplit.first().toIntOrNull()
val suffix = suffixRestSplit.last()
return Element(s, numberPrefix, number, suffix)
}
fun test() {
// define list
// 定义列表
val list = mutableListOf("FOO1", "FOO2", "7foo", "FOO8", "foo5", "foo27_QA", "foo4_1", "foo29_QA", "foo5_1", "foo4")
// create a comparator with defined comparing rules
// 使用定义的比较规则创建比较器
val elementComparator = compareByDescending <Element> { it.numberPrefix }
.thenBy { it.number }
.thenByDescending { it.suffix }
// and sort it with the defined comparator (map it in the fly)
// 使用定义的比较器对其进行排序(在飞行中映射)
val sorted = list
.map { parse(it) } // parse to helper-Element class
.sortedWith(elementComparator) // compare with our defined rules
.map { it.originalValue } // go back to original values
// prints: [7foo, FOO1, FOO2, foo4, foo4_1, foo5, foo5_1, FOO8, foo27_QA, foo29_QA]
// 输出:[7foo, FOO1, FOO2, foo4, foo4_1, foo5, foo5_1, FOO8, foo27_QA, foo29_QA]
println(sorted)
}
英文:
The problem is the order you would like to get.
Default comparator, as well as CASE_INSENSITIVE_ORDER
comparator, follows lexicographic order. But, your expected result is not in such an order.
In lexicographic-case-insensitive order: Foo29_QA
is before foo4
. So the result is fine while using the default comparator.
So, you need to write your own comparator to apply your own logic.
val sorted3 = list.sortedWith { o1, o2 ->
// put your comparing logic here
}
Okey, so how to sort your list (this won't be an easy-peasy task).
I assume that your orders follows the pattern:
>{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}
And we would like to sort it by:
$number_prefix
DESC$number
ASC$alphanumeric_suffix
DESC
So, finally, we can use something like:
// create helper class for comparing
data class Element(
val originalValue: String,
val numberPrefix: Int?,
val number: Int?,
val suffix: String
)
// parse string into Element (for strings that not follow pattern
// `{$number_prefix}{"foo"}{$number}{"_"}{$alphanumeric_suffix}`
// this may throw an exception
fun parse(s: String): Element {
val normalized = s.lowercase()
val fooSplit = normalized.split("foo")
// determine numberPrefix
val numberPrefix = fooSplit.first().toIntOrNull()
// parse the rest
val suffixRest = fooSplit.last()
val suffixRestSplit = suffixRest.split("_")
// and get rest of the data
val number = suffixRestSplit.first().toIntOrNull()
val suffix = suffixRestSplit.last()
return Element(s, numberPrefix, number, suffix)
}
fun test() {
// define list
val list = mutableListOf("FOO1", "FOO2", "7foo", "FOO8", "foo5", "foo27_QA", "foo4_1", "foo29_QA", "foo5_1", "foo4")
// create a comparator with defined comparing rules
val elementComparator = compareByDescending <Element> { it.numberPrefix }
.thenBy { it.number }
.thenByDescending { it.suffix }
// and sort it with the defined comparator (map it in the fly)
val sorted = list
.map { parse(it) } // parse to helper-Element class
.sortedWith(elementComparator) // compare with our defined rules
.map { it.originalValue } // go back to original values
// prints: [7foo, FOO1, FOO2, foo4, foo4_1, foo5, foo5_1, FOO8, foo27_QA, foo29_QA]
println(sorted)
}
答案2
得分: 0
你可以尝试使用此函数来提取数字
fun getNumber(s: String) = ("foo(\\d+)".toRegex().find(s.lowercase())?.groups?.get(1)?.value ?: "0").toInt()
然后你可以执行
val sorted2 = list.sortedWith(compareBy({
getNumber(it)
}, { it }))
英文:
You could try to use this function to extract the number
fun getNumber(s: String) = ("foo(\\d+)".toRegex().find(s.lowercase())?.groups?.get(1)?.value ?: "0").toInt()
then you can do
val sorted2 = list.sortedWith(compareBy({
getNumber(it)
}, { it }))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论