在kotlin中对包含数字的字符串进行排序
Sorting Strings that contains number in kotlin
我想对一些包含数字的字符串进行排序,但排序后变成了这样["s1", "s10", "s11", ... ,"s2", "s21", "s22"]
。在我搜索之后,我发现这个 question 有同样的问题。但在我的示例中,我有 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)
中有错误,请帮我解决这个问题。
根据您发布的数据可能的解决方案:
sortedBy { "s(\d+)".toRegex().matchEntire(it)?.groups?.get(1)?.value?.toInt() }
当然我会将正则表达式移出 lambda,但这样回答更简洁。
您可以使用 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]
当你声明你需要一个 MutableList
, but don't have one yet, you should use sortedBy
or 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
}
)
我为 JSON 排序编写了自定义比较器。它可以改编自 bare 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
}
我想对一些包含数字的字符串进行排序,但排序后变成了这样["s1", "s10", "s11", ... ,"s2", "s21", "s22"]
。在我搜索之后,我发现这个 question 有同样的问题。但在我的示例中,我有 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)
中有错误,请帮我解决这个问题。
根据您发布的数据可能的解决方案:
sortedBy { "s(\d+)".toRegex().matchEntire(it)?.groups?.get(1)?.value?.toInt() }
当然我会将正则表达式移出 lambda,但这样回答更简洁。
您可以使用 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]
当你声明你需要一个 MutableList
, but don't have one yet, you should use sortedBy
or 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
}
)
我为 JSON 排序编写了自定义比较器。它可以改编自 bare 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
}