Як я можу отримати випадкове число в Котліні?


151

Узагальнений метод, який може повернути випадкове ціле число між двома параметрами, як і рубін rand(0..n).

Будь-яка пропозиція?

Відповіді:


375

Моєю пропозицією буде функція розширення на IntRange для створення таких рандов :(0..10).random()

TL; DR Kotlin> = 1,3, один випадковий для всіх платформ

Станом на 1.3, Kotlin має власний багатоплатформенний генератор Random. Це описано в цьому KEEP . Описане нижче розширення тепер є частиною стандартної бібліотеки Котліна , просто використовуйте його так:

val rnds = (0..10).random()

Котлін <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 та інші варіанти

Для котлінгів та інших випадків використання, які не дозволяють використовувати java.util.Random, див. Цю альтернативу .

Також дивіться цю відповідь щодо варіантів моєї пропозиції. Він також включає функцію розширення для випадкових Chars.


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

@SimonForsberg Дійсно. Я додав ще один відповідь , який не використовувати його: stackoverflow.com/a/49507413/8073652
s1m0nw1

Тут також пропонується додати криптографічно захищений генератор псевдовипадкових чисел (CSPRNG) тут: github.com/Kotlin/KEEP/isissue/184
Джонатан Лейтчух

41

Створити випадкове ціле число між 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 (розмір, від, до) замість java-8 .
holi-java

3
Це рішення не працює на Javascript / Native Kotlin. Можливо, було б круто зробити більш загальний метод для цього. :)
Валентин Михалак

@ValentinMichalak ви можете спробувати це: stackoverflow.com/a/49507413/8073652
s1m0nw1

31

Станом на kotlin 1.2, ви можете написати:

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

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


ця корисна для kotlin-native
користувач3471194

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

10

Можливий варіант моєї іншої відповіді для випадкових символів

Для отримання випадкових 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, Котлін має власний багатоплатформенний генератор випадкових випадків. Це описано в цьому KEEP . Тепер ви можете безпосередньо використовувати розширення як частину стандартної бібліотеки Котліна, не визначаючи його:

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

7

Будівництво геть @ s1m0nw1 відмінного відповіді я зробив наступні зміни.

  1. (0..n) передбачає включно в Котліні
  2. (0 до n) передбачає ексклюзивне в Котліні
  3. Використовуйте одиночний об'єкт для випадкового екземпляра (необов'язково)

Код:

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
Ваша перша відповідь мені найбільше подобається. Це ідеальний однолінійний текст, який не вимагає писати жодних функцій розширення
Олексій Семенюк

4

Kotlin> = 1,3, підтримка багатоплатформних для Random

Станом на 1.3, стандартна бібліотека надала багатоплатформенну підтримку рандомів, див. Цю відповідь.

Kotlin <1.3 у JavaScript

Якщо ви працюєте з JavaScript Kotlin і не маєте доступу до них 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()

4

Іншим способом реалізації відповіді s1m0nw1 було б доступ до неї через змінну. Це не більш ефективно, але це позбавляє вас від необхідності вводити ().

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

І тепер до нього можна отримати доступ як такий

(1..10).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

Стандартна lib Kotlin не забезпечує API генератора випадкових чисел. Якщо ви не є багатоплатформою, краще скористатися платформою api (всі інші відповіді на питання говорять про це рішення) .

Але якщо ви перебуваєте в мультиплатформенному контексті, найкращим рішенням є реалізація випадкових власних зусиль у чистому котліні для спільного використання одного і того ж генератора випадкових чисел між платформами. Це простіше для розробників і тестування.

Щоб відповісти на цю проблему в особистому проекті, я реалізую чистий лінійний конгрурентний генератор Котліна . LCG - алгоритм, яким користуються java.util.Random. Перейдіть за цим посиланням, якщо бажаєте ним скористатися: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Моя мета nextInt(range: IntRange)для вас;).

Подбайте про моє призначення, LCG хороший для більшості випадків використання (моделювання, ігри тощо), але не підходить для використання криптографічно через передбачуваність цього методу.


Я вважаю за краще покластись на конкретний код платформи, ніж створити власний випадковий алгоритм. Це трохи нагадує мені про код для java.util.Random, але він не повністю відповідає.
Саймон Форсберг

2

Якщо числа, які ви хочете вибрати, не є послідовними, ви можете використовувати random().

Використання:

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

Повертає одне з номерів, що знаходяться у списку.


2

Більше не потрібно використовувати спеціальні функції розширення. IntRange має random()функцію розширення поза коробки прямо зараз.

val randomNumber = (0..10).random()

2

Використовуючи функцію верхнього рівня, ви можете домогтися того самого синтаксису виклику, що і в Ruby (як хочете):

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

Використання:

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

1

По-перше, вам потрібен RNG. На даний момент у Котліні вам потрібно використовувати конкретні платформи (у них немає вбудованого Kotlin). Для віртуальної машини Java це java.util.Random. Вам потрібно буде створити його примірник, а потім зателефонувати random.nextInt(n).


1

Для отримання випадкового Int числа в Котліні використовуйте наступний метод :

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.