Сортировка строк, содержащих число в котлине

Я хочу отсортировать строки, содержащие числа, но после сортировки он становится таким, как этот ["s1", "s10", "s11", ... ,"s2", "s21", "s22"]. после того, как я ищу, я установил этот вопрос с той же проблемой. но в моем примере у меня есть mutableList<myModel>, и я должен поместить всю строку в myModel.title, например, в изменяемый список и поместить в под кодом:

   val sortData = reversedData.sortedBy {
          //pattern.matcher(it.title).matches()
             Collections.sort(it.title, object : Comparator<String> {
                override fun compare(o1: String, o2: String): Int {
                    return extractInt(o1) - extractInt(o2)
                }

                 fun extractInt(s: String): Int {
                     val num = s.replace("\\D".toRegex(), "")
                     // return 0 if no digits found
                     return if (num.isEmpty()) 0 else Integer.parseInt(num)
                 }
            })
        }

У меня ошибка в .sortedBy и Collections.sort(it.title), пожалуйста, помогите мне исправить это.

«У меня ошибка»: какую?

Henry 10.12.2018 12:49

сначала я должен найти способ преобразовать it.title в изменяемый список. потому что это нужно для Collections.sort. Я не знаю, как вставить все it.title из модели в изменяемый список, а затем я думаю, что должен использовать return перед Collections.sort для исправления .sortedBy

Mehrdad Dolatkhah 10.12.2018 12:59

не смешивайте Collections.sort и sortedBy. Вы можете вместо этого взглянуть на sortWith .... также: sortedBy и sortedWith похожи (они возвращают новый список), тогда как sortWith работает с текущим списком ...

Roland 10.12.2018 13:32

как принятый ответ может быть в ответом на вашу проблему? это слишком сложно, чем любой другой ответ, он использует Observable / Subscriber, чего вы не сделали ...

Roland 11.12.2018 16:19
3
4
4 133
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Возможное решение, основанное на опубликованных вами данных:

sortedBy { "s(\\d+)".toRegex().matchEntire(it)?.groups?.get(1)?.value?.toInt() }

Конечно, я бы переместил регулярное выражение из лямбды, но это более лаконичный ответ.

вы можете использовать sortWith вместо sortBy Например:

class Test(val title:String) {
  override fun toString(): String {
    return "$title"
  }
}

val list = listOf<Test>(Test("s1"), Test("s101"),
Test("s131"), Test("s321"), Test("s23"), Test("s21"), Test("s22"))
val sortData = list.sortedWith( object : Comparator<Test> {
override fun compare(o1: Test, o2: Test): Int {
    return extractInt(o1) - extractInt(o2)
}

fun extractInt(s: Test): Int {
    val num = s.title.replace("\\D".toRegex(), "")
    // return 0 if no digits found
    return if (num.isEmpty()) 0 else Integer.parseInt(num)
}

})

даст результат: [s1, s21, s22, s23, s101, s131, s321]

как я должен поместить все it.title в список и использовать в sortData?

Mehrdad Dolatkhah 10.12.2018 13:15

@MehrdadDolatkhah Я обновляю свой образец, надеюсь, он может дать вам представление о том, как решить вашу проблему, как получить доступ к заголовку (атрибуту). измените класс Test на свой класс MyModel

hakim 10.12.2018 13:53

Поскольку вы заявляете, что вам нужен MutableList, но его еще нет, вы должны использовать sortedBy или sortedWith (в случае, если вы хотите работать с компаратором) вместо этого, и вы получите только (новый) список из вашего текущего, например:

val yourMutableSortedList = reversedData.sortedBy {
  pattern.find(it)?.value?.toInt() ?: 0
}.toMutableList() // now calling toMutableList only because you said you require one... so why don't just sorting it into a new list and returning a mutable list afterwards?

Вы можете использовать compareBy (или Javas Comparator.comparing) для sortedWith.

Если вы просто хотите отсортировать существующий изменяемый список, используйте sortWith (или Collections.sort):

reversedData.sortWith(compareBy {
  pattern.find(it)?.value?.toInt() ?: 0
})

// or using Java imports:
Collections.sort(reversedData, Compatarator.comparingInt {
  pattern.find(it)?.value?.toInt() ?: 0 // what would be the default for non-matching ones?
})

Конечно, вы также можете поиграть с другими помощниками компаратора (например, смешивая последние нули или аналогичные), например:

reversedData.sortWith(nullsLast(compareBy {
  pattern.find(it)?.value
}))

Для примеров выше я использовал следующий Regex:

val pattern = """\d+""".toRegex()
Ответ принят как подходящий

Возможное решение может быть таким:

  reversedData.toObservable()
                    .sorted { o1, o2 ->
                        val pattern = Pattern.compile("\\d+")
                        val matcher = pattern.matcher(o1.title)
                        val matcher2 = pattern.matcher(o2.title)

                        if (matcher.find()) {
                            matcher2.find()
                            val o1Num = matcher.group(0).toInt()
                            val o2Num = matcher2.group(0).toInt()

                            return@sorted o1Num - o2Num
                        } else {
                            return@sorted o1.title?.compareTo(o2.title ?: "") ?: 0
                        }
                    }
                    .toList()
                    .subscribeBy(
                        onError = {
                            it
                        },
                        onSuccess = {
                            reversedData = it
                        }
                    )

Используйте расширения регулярных выражений Kotlin, они короче и проще. Посмотрите мой ответ для примера.

m0skit0 26.12.2018 12:12

Я написал собственный компаратор для сортировки JSON. Его можно адаптировать из простой String / Number / Null

fun getComparator(sortBy: String, desc: Boolean = false): Comparator<SearchResource.SearchResult> {
    return Comparator { o1, o2 ->
        val v1 = getCompValue(o1, sortBy)
        val v2 = getCompValue(o2, sortBy)

        (if (v1 is Float && v2 is Float) {
            v1 - v2
        } else if (v1 is String && v2 is String) {
            v1.compareTo(v2).toFloat()
        } else {
            getCompDefault(v1) - getCompDefault(v2)
        }).sign.toInt() * (if (desc) -1 else 1)
    }
}

private fun getCompValue(o: SearchResource.SearchResult, sortBy: String): Any? {
    val sorter = gson.fromJson<JsonObject>(gson.toJson(o))[sortBy]
    try {
        return sorter.asFloat
    } catch (e: ClassCastException) {
        try {
            return sorter.asString
        } catch (e: ClassCastException) {
            return null
        }
    }
}

private fun getCompDefault(v: Any?): Float {
    return if (v is Float) v else if (v is String) Float.POSITIVE_INFINITY else Float.NEGATIVE_INFINITY
}

Так что адаптируйте свой компаратор и поделитесь адаптированной версией, пожалуйста.

Yazon2006 12.08.2020 21:44

Другие вопросы по теме