¿Cómo puedo obtener un número aleatorio en Kotlin?

151

Un método genérico que puede devolver un entero aleatorio entre 2 parámetros como lo hace Ruby con rand(0..n).

¿Cualquier sugerencia?

Yago Azedias
fuente

Respuestas:

374

Mi sugerencia sería una función de extensión en IntRange para crear randoms como este:(0..10).random()

TL; DR Kotlin> = 1.3, uno aleatorio para todas las plataformas

A partir de 1.3, Kotlin viene con su propio generador aleatorio multiplataforma. Se describe en este MANTENER . La extensión que se describe a continuación ahora es parte de la biblioteca estándar de Kotlin , simplemente úsela así:

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

Kotlin <1.3

Antes de 1.3, en la JVM usamos Randomo incluso ThreadLocalRandomsi estamos en JDK> 1.6.

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

Usado así:

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

Si desea que la función solo regrese 1, 2, ..., 9( 10no incluida), use un rango construido con until:

(0 until 10).random()

Si está trabajando con JDK> 1.6, use en ThreadLocalRandom.current()lugar de Random().

KotlinJs y otras variaciones

Para kotlinjs y otros casos de uso que no permiten el uso de java.util.Random, vea esta alternativa .

Además, vea esta respuesta para ver las variaciones de mi sugerencia. También incluye una función de extensión para Chars aleatorios .

s1m0nw1
fuente
Supongo que esto también usa Java java.util.Random?
Simon Forsberg
@SimonForsberg De hecho.
Agregué
También hay una propuesta aquí para agregar un generador de números pseudoaleatorios
Jonathan Leitschuh
41

Genere un entero aleatorio entre from(inclusivo) y to(exclusivo)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}
Magnus
fuente
1
Si desea obtener un par de Ints aleatorios a distancia , puede usar Random # int (size, from, to) en su lugar en java-8 .
holi-java
3
Esta solución no funciona en Javascript / Native Kotlin. Quizás podría ser genial hacer un método más genérico para hacer esto. :)
Valentin Michalak
@ValentinMichalak puedes probar este: stackoverflow.com/a/49507413/8073652
s1m0nw1
31

A partir de kotlin 1.2, podría escribir:

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

Solo tenga en cuenta que es grande O (n), pero para una lista pequeña (especialmente de valores únicos) está bien: D

mutexkid
fuente
este es útil para kotlin-native
user3471194
11

Puede crear una función de extensión similar a java.util.Random.nextInt(int)una que tome un en IntRangelugar de un Intpara su límite:

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

Ahora puede usar esto con cualquier Randominstancia:

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

Si no desea tener que administrar su propia Randominstancia, puede definir un método conveniente utilizando, por ejemplo ThreadLocalRandom.current():

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

Ahora puede obtener un número entero aleatorio como lo haría en Ruby sin tener que declarar primero una Randominstancia usted mismo:

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

Posible variación a mi otra respuesta para caracteres aleatorios

Para obtener Chars aleatorios , puede definir una función de extensión como esta

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

Si está trabajando con JDK> 1.6, use en ThreadLocalRandom.current() lugar deRandom() .

Para kotlinjs y otros casos de uso que no permiten el uso de java.util.Random, esta respuesta será de ayuda.

Kotlin> = 1.3 soporte multiplataforma para Aleatorio

A partir de 1.3, Kotlin viene con su propio generador aleatorio multiplataforma. Se describe en este MANTENER . Ahora puede usar directamente la extensión como parte de la biblioteca estándar de Kotlin sin definirla:

('a'..'b').random()
s1m0nw1
fuente
7

Partiendo de la excelente respuesta de @ s1m0nw1 , hice los siguientes cambios.

  1. (0..n) implica inclusivo en Kotlin
  2. (0 hasta n) implica exclusivo en Kotlin
  3. Use un objeto singleton para la instancia aleatoria (opcional)

Código:

private object RandomRangeSingleton : Random()

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

Caso de prueba:

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())
                }
        )
    }
Steven Spungin
fuente
5

Ejemplos aleatorios en el rango [1, 10]

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

o utilizando Java Random

val random2 = Random().nextInt(10) + 1
Andrey
fuente
1
Tu primera respuesta me gusta más. Es una frase perfecta que no requiere escribir ninguna función de extensión
Alex Semeniuk
4

Kotlin> = 1.3, soporte multiplataforma para Aleatorio

A partir de 1.3, la biblioteca estándar proporcionó soporte multiplataforma para randoms, consulte esta respuesta.

Kotlin <1.3 en JavaScript

Si está trabajando con Kotlin JavaScript y no tiene acceso java.util.Random, funcionará lo siguiente:

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

Usado así:

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

Otra forma de implementar la respuesta de s1m0nw1 sería acceder a ella a través de una variable. No es que sea más eficiente, pero le ahorra tener que escribir ().

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

Y ahora se puede acceder como tal

(1..10).random
Quinn
fuente
3

En Kotlin 1.3 puedes hacerlo como

val number = Random.nextInt(limit)
desviado
fuente
2

No existe un método estándar que haga esto, pero puede crear fácilmente el suyo usando cualquiera de Math.random()los dos o la clase java.util.Random. Aquí hay un ejemplo usando el Math.random()método:

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

Esta es una salida de muestra:

[9, 8, 1, 7, 5, 6, 9, 8, 1, 9]
[5, 8, 9, 7, 6, 6, 8, 6, 7, 9]
Mahdi AlKhalaf
fuente
2

Kotlin standard lib no proporciona API de generador de números aleatorios. Si no está en un proyecto multiplataforma, es mejor usar la API de plataforma (todas las otras respuestas de la pregunta hablan sobre esta solución) .

Pero si se encuentra en un contexto multiplataforma, la mejor solución es implementar aleatoriamente usted mismo en Kotlin puro para compartir el mismo generador de números aleatorios entre plataformas. Es más simple para desarrolladores y pruebas.

Para responder a este problema en mi proyecto personal, implemento un generador congruencial lineal Kotlin puro . LCG es el algoritmo utilizado por java.util.Random. Sigue este enlace si quieres usarlo: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Mi propósito de implementación nextInt(range: IntRange)para ti;).

Tenga cuidado con mi propósito, LCG es bueno para la mayoría de los casos de uso (simulación, juegos, etc.) pero no es adecuado para el uso criptográfico debido a la previsibilidad de este método.

Valentin Michalak
fuente
Prefiero confiar en el código específico de la plataforma que hacer mi propio algoritmo aleatorio. Esto me recuerda un poco sobre el código de java.util.Random, pero no coincide por completo.
Simon Forsberg
2

Si los números que desea elegir no son consecutivos, puede usarlos random().

Uso:

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

Devuelve uno de los números que están en la lista.

Willi Mentzel
fuente
2

Ya no es necesario usar funciones de extensión personalizadas. IntRange tiene una random()función de extensión lista para usar ahora.

val randomNumber = (0..10).random()
Willi Mentzel
fuente
2

Usando una función de nivel superior, puede lograr exactamente la misma sintaxis de llamada que en Ruby (como lo desee):

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

Uso:

rand(1, 3) // returns either 1, 2 or 3
Willi Mentzel
fuente
1

Primero, necesitas un RNG. En Kotlin actualmente necesita usar los específicos de la plataforma (no hay un Kotlin integrado en uno). Para la JVM es java.util.Random. Tendrá que crear una instancia y luego llamar random.nextInt(n).

Mibac
fuente
1

Para obtener un número Int aleatorio en Kotlin, use el siguiente método :

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

Espero que esto ayude.

Andy Fedoroff
fuente
0

Podría crear una función de extensión:

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

Valor de flotación redonda:

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

Uso del método:

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

Salida:

valor: 0.0 valor: 0.1 valor: 0.2 valor: 0.3 valor: 0.4 valor: 0.5 valor: 0.6 valor: 0.7 valor: 0.8 valor: 0.9 valor: 1.0

rodrigosimoesrosa
fuente
0

Código fuente completo Puede controlar si se permiten duplicados.

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("")
        }
    }
}
Vincent Sit
fuente
0

Siempre que haya una situación en la que desee generar una clave o una dirección mac que sea un número hexadecimal que tenga dígitos basados ​​en la demanda del usuario, y que también use Android y Kotlin, entonces mi código a continuación lo ayudará:

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()
} 
Rupesh Gaud
fuente
-1

ser súper tonto))

 fun rnd_int(min: Int, max: Int): Int {
        var max = max
        max -= min
        return (Math.random() * ++max).toInt() + min
    }
Deomin Dmitriy
fuente