按字符和长度排序字符串

8
在我的安卓应用程序中,我正在尝试按照1、2、3等顺序对公交路线标签进行排序。
为此,我正在使用以下代码:
Collections.sort(directions, Comparator { lhs, rhs ->
        var obj1 = lhs.short_names.firstOrNull() ?: ""
        var obj2 = rhs.short_names.firstOrNull() ?: ""

        if (obj1 === obj2) {
            obj1 = lhs.headsigns.firstOrNull() ?: ""
            obj2 = rhs.headsigns.firstOrNull() ?: ""
            if (obj1 === obj2) {
                return@Comparator 0
            }
            obj1.compareTo(obj2)
        } else {
            obj1.compareTo(obj2)
        }

我遇到的问题是它会排序,但会遇到以下情况:1, 2, 3, 30, 31, 4, 5。

我应该如何更改以获得正确的排序。

1个回答

9
如果您只需要简单的数字比较,可以像这样做。
directions.sortWith(Comparator { lhs, rhs ->
  val i1 = lhs.toInt()
  val i2 = rhs.toInt()
  when {
    i1 < i2 -> -1
    i1 > i2 -> 1
    else -> 0
  }
})

正如hotkey所指出的那样,上面的代码可以用几乎相同的实现替换,看起来更加简单。

directions.sortBy { it.toInt() }

这个算法的通用版本称为“alphanum排序”,在这里详细描述。我制作了一个Kotlin版本的此算法,您可以使用它。它比您所需的更复杂,但它可以解决您的问题。

class AlphanumComparator : Comparator<String> {
  override fun compare(s1: String, s2: String): Int {
    var thisMarker = 0
    var thatMarker = 0
    val s1Length = s1.length
    val s2Length = s2.length

    while (thisMarker < s1Length && thatMarker < s2Length) {
      val thisChunk = getChunk(s1, s1Length, thisMarker)
      thisMarker += thisChunk.length

      val thatChunk = getChunk(s2, s2Length, thatMarker)
      thatMarker += thatChunk.length

      // If both chunks contain numeric characters, sort them numerically.
      var result: Int
      if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
        // Simple chunk comparison by length.
        val thisChunkLength = thisChunk.length
        result = thisChunkLength - thatChunk.length
        // If equal, the first different number counts.
        if (result == 0) {
          for (i in 0..thisChunkLength - 1) {
            result = thisChunk[i] - thatChunk[i]
            if (result != 0) {
              return result
            }
          }
        }
      } else {
        result = thisChunk.compareTo(thatChunk)
      }

      if (result != 0) {
        return result
      }
    }

    return s1Length - s2Length
  }

  private fun getChunk(string: String, length: Int, marker: Int): String {
    var current = marker
    val chunk = StringBuilder()
    var c = string[current]
    chunk.append(c)
    current++
    if (isDigit(c)) {
      while (current < length) {
        c = string[current]
        if (!isDigit(c)) {
          break
        }
        chunk.append(c)
        current++
      }
    } else {
      while (current < length) {
        c = string[current]
        if (isDigit(c)) {
          break
        }
        chunk.append(c)
        current++
      }
    }
    return chunk.toString()
  }

  private fun isDigit(ch: Char): Boolean {
    return '0' <= ch && ch <= '9'
  }
}

要使用这个Comparator,只需调用
directions.sortWith(AlphanumComparator())

如果您不需要使用Kotlin编码,只需在Dave Koelle的页面上获取原始Java版本即可。而算法的Kotlin版本也可以在GitHub上找到。


1
第一个使用 toInt() 的解决方案可以重写为 a.sortBy { it.toInt() } - hotkey
@AnthonyTaylor,你不需要使用Collections.sort()。只需调用directions.sortWith(AlphanumComparator())即可。 - Michael
@Michael,我相信这是我脑海中的字符串 编辑fun getDirectionsForRoute(routeId: Int) : Observable<List<Direction>>获取路线方向:Observable<List<Direction>>fun getDirection(routeId: Int, directionId: Int) : Observable<Direction>获取方向:Observable<Direction>所以看起来是整数(我正在使用别人的代码,对此不太了解,抱歉)。 - Anthony Taylor
你的列表是不可变的。在这种情况下,你可以这样做:val sortedDirections = directions.sortedWith(AlphanumComparator()) - Michael
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Anthony Taylor
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接