Как я могу получить случайное число в Котлине?


171

Общий метод, который может возвращать случайное целое число между двумя параметрами, как это делает ruby rand(0..n).

Любое предложение?

Ответы:


415

Мое предложение - это функция расширения IntRange для создания таких случайных чисел :(0..10).random()

TL; DR Kotlin> = 1.3, один случайный для всех платформ

Начиная с версии 1.3, Kotlin поставляется с собственным мультиплатформенным генератором случайных чисел. Это описано в этом KEEP . Описанное ниже расширение теперь является частью стандартной библиотеки Kotlin , просто используйте его так:

val rnds = (0..10).random() // generated random from 1 to 9 included

Котлин <1,3

До версии 1.3 мы использовали JVM Randomили даже ThreadLocalRandomесли у нас JDK> 1.6.

fun IntRange.random() = 
       Random().nextInt((endInclusive + 1) - start) + start

Используется так:

// will return an `Int` between 0 and 10 (incl.)
(0..10).random()

Если вы хотите, чтобы функция только возвращала 1, 2, ..., 9( 10не включалась), используйте диапазон, построенный с помощью until:

(0 until 10).random()

Если вы работаете с JDK> 1.6, используйте ThreadLocalRandom.current()вместо Random().

KotlinJs и другие варианты

Для kotlinjs и других вариантов использования, которые не позволяют использовать java.util.Random, см. Эту альтернативу .

Также см. Этот ответ для вариантов моего предложения. Он также включает функцию расширения для случайных Chars.


Я предполагаю, что это также использует Java java.util.Random?
Саймон Форсберг

@SimonForsberg Верно. Я добавил еще один ответ, в котором он не используется: stackoverflow.com/a/49507413/8073652
s1m0nw1,

Здесь также есть предложение добавить сюда криптографически безопасный генератор псевдослучайных чисел (CSPRNG): github.com/Kotlin/KEEP/issues/184
Джонатан Лейтшу

val rnds = (0..10).random() фактически генерирует от 0 до 10, включая 10 и 0 . pl.kotl.in/1o8LyD1Dc
xst,

42

Сгенерировать случайное целое число между from(включительно) и to(исключая)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}

1
Если вы хотите получить пару рандомных случайных Ints, вы можете использовать Random # int (size, from, to) вместо java-8 .
holi-java

4
Это решение не работает на Javascript / Native Kotlin. Возможно, было бы круто создать для этого более общий метод. :)
Валентин Михалак

@ValentinMichalak, вы можете попробовать это: stackoverflow.com/a/49507413/8073652
s1m0nw1

31

Начиная с kotlin 1.2, вы могли написать:

(1..3).shuffled().last()

Просто имейте в виду, что это большой O (n), но для небольшого списка (особенно уникальных значений) все в порядке: D


это полезно для kotlin-native
user3471194

11

Вы можете создать функцию расширения, аналогичную java.util.Random.nextInt(int)той, которая принимает IntRangeвместо Intпривязки:

fun Random.nextInt(range: IntRange): Int {
    return range.start + nextInt(range.last - range.start)
}

Теперь вы можете использовать это с любым Randomэкземпляром:

val random = Random()
println(random.nextInt(5..9)) // prints 5, 6, 7, or 8

Если вы не хотите управлять своим собственным Randomэкземпляром, вы можете определить удобный метод, используя, например ThreadLocalRandom.current(),:

fun rand(range: IntRange): Int {
    return ThreadLocalRandom.current().nextInt(range)
}

Теперь вы можете получить случайное целое число, как в Ruby, без предварительного объявления Randomэкземпляра самостоятельно:

rand(5..9) // returns 5, 6, 7, or 8

11

Возможное изменение моего другого ответа для случайных символов

Чтобы получить случайные Chars, вы можете определить функцию расширения, подобную этой

fun ClosedRange<Char>.random(): Char = 
       (Random().nextInt(endInclusive.toInt() + 1 - start.toInt()) + start.toInt()).toChar()

// will return a `Char` between A and Z (incl.)
('A'..'Z').random()

Если вы работаете с JDK> 1.6, используйте ThreadLocalRandom.current() вместо Random().

Для kotlinjs и других случаев применения , которые не позволяют использование java.util.Random, этот ответ поможет.

Kotlin> = 1.3 мультиплатформенная поддержка Random

Начиная с версии 1.3, Kotlin имеет собственный мультиплатформенный генератор случайных чисел. Это описано в этом KEEP . Теперь вы можете напрямую использовать расширение как часть стандартной библиотеки Kotlin, не определяя его:

('a'..'b').random()

7

Основываясь на отличном ответе @ s1m0nw1, я внес следующие изменения.

  1. (0..n) подразумевает включительно в Котлине
  2. (От 0 до n) подразумевает исключение в Котлине
  3. Используйте одноэлементный объект для экземпляра Random (необязательно)

Код:

private object RandomRangeSingleton : Random()

fun ClosedRange<Int>.random() = RandomRangeSingleton.nextInt((endInclusive + 1) - start) + start

Прецедент:

fun testRandom() {
        Assert.assertTrue(
                (0..1000).all {
                    (0..5).contains((0..5).random())
                }
        )
        Assert.assertTrue(
                (0..1000).all {
                    (0..4).contains((0 until 5).random())
                }
        )
        Assert.assertFalse(
                (0..1000).all {
                    (0..4).contains((0..5).random())
                }
        )
    }

5

Примеры случайны в диапазоне [1, 10]

val random1 = (0..10).shuffled().last()

или используя Java Random

val random2 = Random().nextInt(10) + 1

1
Ваш первый ответ мне нравится больше всего. Это идеальный однострочник, который не требует написания каких-либо функций расширения
Алекс Семенюк

@AlexSemeniuk, пожалуйста, не надо. shuffled()вернет список. Только представьте, что произойдет, если вы пройдете мимо(0..Integer.MAX_VALUE)
девиант

@deviant Хороший момент. Просто у меня был вариант использования, когда мне нужно было получить случайный элемент из коллекции.
Алекс Семенюк,

5

Kotlin> = 1.3, мультиплатформенная поддержка Random

Начиная с версии 1.3 стандартная библиотека обеспечивала мультиплатформенную поддержку случайных чисел, см. Этот ответ.

Kotlin <1.3 на JavaScript

Если вы работаете с Kotlin JavaScript и не имеете доступа к нему java.util.Random, будет работать следующее:

fun IntRange.random() = (Math.random() * ((endInclusive + 1) - start) + start).toInt()

Используется так:

// will return an `Int` between 0 and 10 (incl.)
(0..10).random()

5

Другой способ реализации ответа s1m0nw1 - доступ к нему через переменную. Не то чтобы это более эффективно, но избавляет от необходимости вводить ().

val ClosedRange<Int>.random: Int
    get() = Random().nextInt((endInclusive + 1) - start) +  start 

И теперь он доступен как таковой

(1..10).random


3

Если числа, которые вы хотите выбрать, не идут подряд, вы можете использовать random().

Применение:

val list = listOf(3, 1, 4, 5)
val number = list.random()

Возвращает одно из чисел в списке.


2

Стандартного метода для этого не существует, но вы можете легко создать свой собственный, используя либо Math.random()класс, либо класс java.util.Random. Вот пример использования Math.random()метода:

fun random(n: Int) = (Math.random() * n).toInt()
fun random(from: Int, to: Int) = (Math.random() * (to - from) + from).toInt()
fun random(pair: Pair<Int, Int>) = random(pair.first, pair.second)

fun main(args: Array<String>) {
    val n = 10

    val rand1 = random(n)
    val rand2 = random(5, n)
    val rand3 = random(5 to n)

    println(List(10) { random(n) })
    println(List(10) { random(5 to n) })
}

Это пример вывода:

[9, 8, 1, 7, 5, 6, 9, 8, 1, 9]
[5, 8, 9, 7, 6, 6, 8, 6, 7, 9]

2

Стандартная библиотека Kotlin не предоставляет API генератора случайных чисел. Если вы не участвуете в многоплатформенном проекте, лучше использовать API платформы (все остальные ответы на вопрос говорят об этом решении) .

Но если вы находитесь в многоплатформенном контексте, лучшее решение - реализовать random самостоятельно в чистом котлине для совместного использования одного и того же генератора случайных чисел между платформами. Это проще для разработки и тестирования.

Чтобы ответить на эту проблему в моем личном проекте, я реализовал чистый Kotlin Linear Congruential Generator . LCG - это алгоритм, используемый java.util.Random. Перейдите по этой ссылке, если хотите ее использовать: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Моя цель реализации nextInt(range: IntRange)для вас;).

Позаботьтесь о моей цели, LCG подходит для большинства случаев использования (моделирование, игры и т. Д.), Но не подходит для криптографического использования из-за предсказуемости этого метода.


Я бы предпочел полагаться на код конкретной платформы, чем создавать свой собственный случайный алгоритм. Это немного напоминает мне код для java.util.Random, но не полностью совпадает.
Саймон Форсберг


2

Используя функцию верхнего уровня, вы можете добиться того же синтаксиса вызова, что и в Ruby (как хотите):

fun rand(s: Int, e: Int) = Random.nextInt(s, e + 1)

Применение:

rand(1, 3) // returns either 1, 2 or 3

1

Во-первых, вам нужен ГСЧ. В Kotlin в настоящее время вам нужно использовать платформы, специфичные для платформы (в Kotlin нет встроенного). Для JVM это java.util.Random. Вам нужно будет создать его экземпляр, а затем вызвать random.nextInt(n).


1

Чтобы получить случайное число Int в Kotlin, используйте следующий метод :

import java.util.concurrent.ThreadLocalRandom

fun randomInt(rangeFirstNum:Int, rangeLastNum:Int) {
    val randomInteger = ThreadLocalRandom.current().nextInt(rangeFirstNum,rangeLastNum)
    println(randomInteger)
}
fun main() {    
    randomInt(1,10)
}


// Result – random Int numbers from 1 to 9

Надеюсь это поможет.


0

Вы можете создать функцию расширения:

infix fun ClosedRange<Float>.step(step: Float): Iterable<Float> {
    require(start.isFinite())
    require(endInclusive.isFinite())
    require(step.round() > 0.0) { "Step must be positive, was: $step." }
    require(start != endInclusive) { "Start and endInclusive must not be the same"}

    if (endInclusive > start) {
        return generateSequence(start) { previous ->
            if (previous == Float.POSITIVE_INFINITY) return@generateSequence null
            val next = previous + step.round()
            if (next > endInclusive) null else next.round()
        }.asIterable()
    }

    return generateSequence(start) { previous ->
        if (previous == Float.NEGATIVE_INFINITY) return@generateSequence null
        val next = previous - step.round()
        if (next < endInclusive) null else next.round()
    }.asIterable()
}

Круглое значение с плавающей запятой:

fun Float.round(decimals: Int = DIGITS): Float {
    var multiplier = 1.0f
    repeat(decimals) { multiplier *= 10 }
    return round(this * multiplier) / multiplier
}

Использование метода:

(0.0f .. 1.0f).step(.1f).forEach { System.out.println("value: $it") }

Выход:

значение: значение 0,0: значение 0,1: значение 0,2: значение 0,3: значение 0,4: значение 0,5: значение 0,6: значение 0,7: значение 0,8: значение 0,9: 1,0


0

Полный исходный код. Может контролировать, разрешены ли дубликаты.

import kotlin.math.min

abstract class Random {

    companion object {
        fun string(length: Int, isUnique: Boolean = false): String {
            if (0 == length) return ""
            val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') // Add your set here.

            if (isUnique) {
                val limit = min(length, alphabet.count())
                val set = mutableSetOf<Char>()
                do { set.add(alphabet.random()) } while (set.count() != limit)
                return set.joinToString("")
            }
            return List(length) { alphabet.random() }.joinToString("")
        }

        fun alphabet(length: Int, isUnique: Boolean = false): String {
            if (0 == length) return ""
            val alphabet = ('A'..'Z')
            if (isUnique) {
                val limit = min(length, alphabet.count())
                val set = mutableSetOf<Char>()
                do { set.add(alphabet.random()) } while (set.count() != limit)
                return set.joinToString("")
            }

            return List(length) { alphabet.random() }.joinToString("")
        }
    }
}

0

Всякий раз, когда возникает ситуация, когда вы хотите сгенерировать ключ или MAC-адрес, который представляет собой шестнадцатеричное число с цифрами на основе запроса пользователя, и это тоже с использованием android и kotlin, тогда мой приведенный ниже код поможет вам:

private fun getRandomHexString(random: SecureRandom, numOfCharsToBePresentInTheHexString: Int): String {
    val sb = StringBuilder()
    while (sb.length < numOfCharsToBePresentInTheHexString) {
        val randomNumber = random.nextInt()
        val number = String.format("%08X", randomNumber)
        sb.append(number)
    }
    return sb.toString()
} 

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.