Идиоматический способ генерации случайной буквенно-цифровой строки в Котлине

Я могу создать случайную последовательность чисел в определенном диапазоне, например:

fun ClosedRange<Int>.random() = Random().nextInt(endInclusive - start) +  start
fun generateRandomNumberList(len: Int, low: Int = 0, high: Int = 255): List<Int> {
  (0..len-1).map {
    (low..high).random()
  }.toList()
}

Затем мне придется растягивать List с помощью

fun List<Char>.random() = this[Random().nextInt(this.size)]

Тогда я могу сделать:

fun generateRandomString(len: Int = 15): String{
  val alphanumerics = CharArray(26) { it -> (it + 97).toChar() }.toSet()
      .union(CharArray(9) { it -> (it + 48).toChar() }.toSet())
  return (0..len-1).map {
      alphanumerics.toList().random()
  }.joinToString("")
}

Но может быть, лучший способ?

Ответ 1

Предполагая, что у вас есть определенный набор исходных символов (source в этом фрагменте), вы можете сделать это:

val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
java.util.Random().ints(outputStrLength, 0, source.length)
        .asSequence()
        .map(source::get)
        .joinToString("")

Что дает строки типа "LYANFGNPNI" для outputStrLength = 10.

Два важных бита

  1. Random().ints(length, minValue, maxValue) который создает поток случайных чисел длиной от minValue до maxValue-1, и
  2. asSequence() которая преобразует не очень полезный IntStream в гораздо более полезную Sequence<Int>.

Ответ 2

Ленивые люди просто делали

java.util.UUID.randomUUID().toString()

Вы не можете ограничить диапазон символов здесь, но я думаю, что это нормально во многих ситуациях.

Ответ 3

Начиная с Kotlin 1.3 вы можете сделать это:

fun getRandomString(length: Int) : String {
    val allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"
    return (1..length)
        .map { allowedChars.random() }
        .joinToString("")
}

Ответ 4

Без JDK8:

fun ClosedRange<Char>.randomString(lenght: Int) = 
    (1..lenght)
        .map { (Random().nextInt(endInclusive.toInt() - start.toInt()) + start.toInt()).toChar() }
        .joinToString("")

использование:

('a'..'z').randomString(6)

Ответ 5

('A'..'z').map { it }.shuffled().subList(0, 4).joinToString("")

Ответ 6

Использование Kotlin 1.3:

Этот метод использует ввод желаемой длины строки требуемой desiredStrLength как целое число и возвращает случайную буквенно-цифровую строку желаемой длины строки.

fun randomAlphaNumericString(desiredStrLength: Int): String {
    val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')

    return (1..desiredStrLength)
        .map{ kotlin.random.Random.nextInt(0, charPool.size) }
        .map(charPool::get)
        .joinToString("")
}

Если вы предпочитаете неизвестную длину буквенно-цифровой (или, по крайней мере, достаточно длинную строку, например, 36 в моем примере ниже), этот метод можно использовать:

fun randomAlphanumericString(): String {
    val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
    val outputStrLength = (1..36).shuffled().first()

    return (1..outputStrLength)
        .map{ kotlin.random.Random.nextInt(0, charPool.size) }
        .map(charPool::get)
        .joinToString("")
}

Ответ 7

Или используйте API-интерфейс coroutine для истинного духа Котлина:

buildSequence { val r = Random(); while(true) yield(r.nextInt(24)) }
   .take(10)
   .map{(it+ 65).toChar()}
   .joinToString("")

Ответ 8

Основываясь на ответе Пола Хикса, я хотел использовать пользовательскую строку в качестве входных данных. В моем случае прописные и строчные буквенно-цифровые символы. Random().ints(...) также не работал для меня, так как для его использования требовался уровень API 24 на Android.

Вот как я делаю это с абстрактным классом Kotlin Random:

import kotlin.random.Random

object IdHelper {

    private val ALPHA_NUMERIC = ('0'..'9') + ('A'..'Z') + ('a'..'z')
    private const val LENGTH = 20

    fun generateId(): String {
        return List(LENGTH) { Random.nextInt(0, ALPHA_NUMERIC.size) }
                .map { ALPHA_NUMERIC[it] }
                .joinToString(separator = "")
    }
}

Процесс и то, как это работает, похож на многие другие ответы, уже размещенные здесь:

  1. Создайте список чисел длины LENGTH которые соответствуют значениям индекса строки источника, который в этом случае является ALPHA_NUMERIC
  2. Сопоставьте эти числа с исходной строкой, преобразовав каждый числовой индекс в символьное значение.
  3. Преобразуйте полученный список символов в строку, соединив их с пустой строкой в качестве символа-разделителя.
  4. Вернуть полученную строку.

Использовать легко, просто вызовите его как статическую функцию: IdHelper.generateId()

Ответ 9

fun randomAlphaNumericString(@IntRange(from = 1, to = 62) lenght: Int): String {
    val alphaNumeric = ('a'..'z') + ('A'..'Z') + ('0'..'9')
    return alphaNumeric.shuffled().take(lenght).joinToString("")
}

Ответ 10

Лучший способ, я думаю:

fun generateID(size: Int): String {
    val source = "A1BCDEF4G0H8IJKLM7NOPQ3RST9UVWX52YZab1cd60ef2ghij3klmn49opq5rst6uvw7xyz8"
    return (source).map { it }.shuffled().subList(0, size).joinToString("")
}

Ответ 11

Использование Collection.random() из Kotlin 1.3:

// Descriptive alphabet using three CharRange objects, concatenated
val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')

// Build list from 20 random samples from the alphabet,
// and convert it to a string using "" as element separator
val randomString: String = List(20) { alphabet.random() }.joinToString("")