Преобразовать коллекцию чисел в диапазон форматированной строки с помощью Kotlin - PullRequest
0 голосов
/ 11 июля 2019

У меня очень большой список чисел.Мне нужно передать этот список номеров в качестве параметра запроса URL.Поскольку эти списки могут быть настолько большими, это может привести к тому, что URL-адрес запроса превысит допустимую длину URL-адреса ;также немного сложно отладить строку последовательных чисел (EG 1,2,3,..,500,782).Чтобы устранить эти проблемы, я хотел бы преобразовать строку списка последовательных чисел в строку, отформатированную с использованием обозначения диапазона (EG -5..-3,1..500,782).Как мне создать эту строку обозначения диапазона, используя Kotlin, и как мне разобрать строку обратно в набор чисел, также используя Kotlin?

1 Ответ

0 голосов
/ 11 июля 2019

Это преобразует 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<Int>:

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

... и, наконец, даже лучше, чем использование огромной коллекции чисел, вы можете использовать класс 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())

...