Я хочу отсортировать строки, содержащие числа, но после сортировки он становится таким, как этот ["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), пожалуйста, помогите мне исправить это.
сначала я должен найти способ преобразовать it.title в изменяемый список. потому что это нужно для Collections.sort. Я не знаю, как вставить все it.title из модели в изменяемый список, а затем я думаю, что должен использовать return перед Collections.sort для исправления .sortedBy
не смешивайте Collections.sort и sortedBy. Вы можете вместо этого взглянуть на sortWith .... также: sortedBy и sortedWith похожи (они возвращают новый список), тогда как sortWith работает с текущим списком ...
как принятый ответ может быть в ответом на вашу проблему? это слишком сложно, чем любой другой ответ, он использует Observable / Subscriber, чего вы не сделали ...
Возможное решение, основанное на опубликованных вами данных:
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?
@MehrdadDolatkhah Я обновляю свой образец, надеюсь, он может дать вам представление о том, как решить вашу проблему, как получить доступ к заголовку (атрибуту). измените класс Test на свой класс MyModel
Поскольку вы заявляете, что вам нужен 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, они короче и проще. Посмотрите мой ответ для примера.
Я написал собственный компаратор для сортировки 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
}
Так что адаптируйте свой компаратор и поделитесь адаптированной версией, пожалуйста.
«У меня ошибка»: какую?