【问题标题】:Sorting Strings that contains number in kotlin在kotlin中对包含数字的字符串进行排序
【发布时间】:2019-05-11 07:30:11
【问题描述】:

我想对一些包含数字的字符串进行排序,但排序后,它变成了这样["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)
                 }
            })
        }

我在.sortedByCollections.sort(it.title) 中有一个错误,请帮我解决这个问题。

【问题讨论】:

  • “我有一个错误”:你会透露哪一个?
  • 首先,我必须想办法将 it.title 转换为可变列表。因为 Collections.sort 需要它。我不知道如何将模型中的所有 it.title 推送到可变列表中,然后我认为我必须在 Collections.sort 之前使用 return 来修复 .sortedBy
  • 不要混用 Collections.sortsortedBy。你可能想看看sortWith 代替......还有:sortedBysortedWith 是相似的(它们返回一个新列表),而sortWith 在当前列表上运行......
  • 接受的答案如何回答您的问题?它比任何其他答案都太复杂了,它使用Observable/Subscriber,你没有...

标签: android collections kotlin mutablelist


【解决方案1】:

基于您发布的数据的可能解决方案:

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

当然,我会将正则表达式移出 lambda,但这样会更简洁。

【讨论】:

    【解决方案2】:

    您可以使用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 我更新了我的示例,希望它可以让您了解如何解决您的问题,如何访问标题(属性)。用你的 MyModel 类更改类 Test
    【解决方案3】:

    当您声明您需要一个 MutableList,但还没有一个时,您应该使用 sortedBysortedWith(如果您想使用比较器),而您只会得到一个 (新)列出您当前的列表,例如:

    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()
    

    【讨论】:

      【解决方案4】:

      一个可能的解决方案是这样的:

        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 的正则表达式扩展,它们更短更简单。以我的回答为例。
      【解决方案5】:

      我为我的 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
      }
      

      【讨论】:

      • 所以请调整您的比较器并分享调整后的版本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-18
      • 2011-09-10
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多