【问题标题】:Convert collection of numbers to range formatted string with Kotlin使用 Kotlin 将数字集合转换为范围格式的字符串
【发布时间】:2019-07-10 23:19:51
【问题描述】:

我有一个非常大的数字列表。我需要将此数字列表作为 URL 查询参数传递。由于这些列表可能会变得如此之大,因此可能会导致请求 URL 超过 the allowed length of a URL;此外,调试一串序列号(例如1,2,3,..,500,782)有点困难。为了解决这些问题,我想将序列号列表字符串转换为使用范围表示法格式化的字符串(例如-5..-3,1..500,782)。如何使用 Kotlin 创建这个范围表示法字符串,以及如何使用 Kotlin 将字符串解析回数字集合?

【问题讨论】:

    标签: kotlin collections numbers format tostring


    【解决方案1】:

    这会将Collection<Int> 转换为使用指定“范围表示法”的字符串:

    fun Collection<Int>.toRangesString(): String {
      if (this.isEmpty()) {
        return ""
      }
    
    
      if (this.size <= 2) {
        return this.toSortedSet().joinToString(",")
      }
    
    
      val rangeStrings = mutableListOf<String>()
    
      var start: Int? = null
      var prev: Int? = null
    
      for (num in this.toSortedSet()) {
        if (prev == null) {
          start = num
          prev = num
          continue
        }
    
        if (num != (prev + 1)) {
          _addRangeString(rangeStrings, start!!, prev)
          start = num
          prev = num
          continue
        }
    
        prev = num
      }
    
      if (start != null) {
        _addRangeString(rangeStrings, start, prev!!)
      }
    
      return rangeStrings.joinToString(",")
    }
    
    
    private fun _addRangeString(rangeStrings: MutableList<String>, start: Int, prev: Int) {
      rangeStrings.add(
        when {
          (start == prev) -> start.toString()
          ((start + 1) == prev) -> "${start},${prev}"
          else -> "${start}..${prev}"
        }
      )
    }
    

    ...这会将这些范围标记的字符串解析为Set&lt;Int&gt;

    fun parseRangesString(str: String): Set<Int> {
      if (str.isBlank()) {
        return setOf()
      }
    
    
      val ranges = str.trim().split(",")
      val numbers = mutableListOf<Int>()
    
      for (range in ranges) {
        if (range.contains("..")) {
          val (start, end) = range.split("..")
          numbers.addAll(start.toInt()..end.toInt())
          continue
        }
    
        numbers.add(range.toInt())
      }
    
      return numbers.toSet()
    }
    

    ...最后,你可以使用 Kotlin 的 IntRange(或 LongRange)类,甚至比使用大量数字更好:

    fun toIntRanges(str: String): Collection<IntRange> = _toRanges(str, ::_createIntRange)
    fun toLongRanges(str: String): Collection<LongRange> = _toRanges(str, ::_createLongRange)
    
    private fun <T : ClosedRange<*>> _toRanges(str: String, createRange: (start: String, end: String) -> T): Collection<T> {
      if (str.isBlank()) {
        return listOf()
      }
    
      val rangeStrs = str.trim().split(",")
      val ranges = mutableListOf<T>()
    
      for (rangeStr in rangeStrs) {
        if (rangeStr.contains("..")) {
          val (start, end) = rangeStr.split("..")
          ranges.add(createRange(start, end))
          continue
        }
    
        ranges.add(createRange(rangeStr, rangeStr))
      }
    
      return ranges.toList()
    }
    
    
    private fun _createIntRange(start: String, end: String) = IntRange(start.toInt(), end.toInt())
    private fun _createLongRange(start: String, end: String) = LongRange(start.toLong(), end.toLong())
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-08
      • 2022-09-21
      • 1970-01-01
      • 1970-01-01
      • 2019-01-13
      • 2022-07-20
      • 2021-11-11
      • 2017-01-28
      相关资源
      最近更新 更多