如何在Kotlin中对包含数字和特殊字符的字符串列表进行排序

huangapple go评论62阅读模式
英文:

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_QAfoo4 之前。因此,在使用默认比较器时,结果是正确的。"

"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 }))

huangapple
  • 本文由 发表于 2023年3月1日 14:40:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600298.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定