Come posso ottenere un numero casuale in Kotlin?


151

Un metodo generico che può restituire un numero intero casuale tra 2 parametri come fa ruby rand(0..n).

Qualche suggerimento?

Risposte:


373

Il mio suggerimento sarebbe una funzione di estensione su IntRange per creare randoms in questo modo:(0..10).random()

TL; DR Kotlin> = 1.3, un casuale per tutte le piattaforme

A partire da 1.3, Kotlin viene fornito con un proprio generatore casuale multipiattaforma. È descritto in questo MANTENERE . L'estensione descritta di seguito fa ora parte della libreria standard di Kotlin , semplicemente usala in questo modo:

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

Kotlin <1.3

Prima della 1.3, su JVM utilizziamo Randomo anche ThreadLocalRandomse siamo su JDK> 1.6.

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

Usato così:

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

Se si desidera restituire la funzione 1, 2, ..., 9( 10non inclusa), utilizzare un intervallo costruito con until:

(0 until 10).random()

Se lavori con JDK> 1.6, usa ThreadLocalRandom.current()invece di Random().

KotlinJs e altre varianti

Per kotlinjs e altri casi d'uso che non ne consentono l'utilizzo java.util.Random, vedere questa alternativa .

Inoltre, vedi questa risposta per le variazioni del mio suggerimento. Include anche una funzione di estensione per messaggi casuali Char.


Presumo che questo usi anche Java java.util.Random?
Simon Forsberg,

@SimonForsberg Infatti. Ho aggiunto un'altra risposta che non fa uso di esso: stackoverflow.com/a/49507413/8073652
s1m0nw1

C'è anche una proposta qui per aggiungere un generatore di numeri pseudo-casuali crittograficamente sicuro (CSPRNG) qui: github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh

41

Genera un numero intero casuale tra from(compreso) e to(esclusivo)

import java.util.Random

val random = Random()

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

1
Se vuoi ottenere un paio di casuali a distanza Int, puoi usare Random # int (size, from, to) invece in java-8 .
holi-java,

3
Questa soluzione non funziona su Javascript / Native Kotlin. Forse potrebbe essere bello creare un metodo più generico per farlo. :)
Valentin Michalak il

@ValentinMichalak si può provare questo: stackoverflow.com/a/49507413/8073652
s1m0nw1

31

A partire da kotlin 1.2, potresti scrivere:

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

Basta essere consapevoli che è grande O (n), ma per un piccolo elenco (soprattutto di valori univoci) va bene: D


questo è utile per kotlin-native
user3471194

11

È possibile creare una funzione di estensione simile a java.util.Random.nextInt(int)quella che utilizza IntRangeinvece di una Intper il suo limite:

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

Ora puoi usarlo con qualsiasi Randomistanza:

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

Se non si desidera gestire la propria Randomistanza, è possibile definire un metodo di convenienza utilizzando, ad esempio ThreadLocalRandom.current():

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

Ora puoi ottenere un numero intero casuale come faresti in Ruby senza dover prima dichiarare Randomun'istanza tu stesso:

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

10

Possibile variazione alla mia altra risposta per caratteri casuali

Per ottenere messaggi casuali Char, puoi definire una funzione di estensione come questa

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

Se lavori con JDK> 1.6, usa ThreadLocalRandom.current() invece di Random().

Per kotlinjs e altri casi d'uso che non ne consentono l'utilizzo java.util.Random, questa risposta sarà di aiuto.

Kotlin> = 1.3 supporto multipiattaforma per Random

A partire da 1.3, Kotlin viene fornito con un proprio generatore casuale multipiattaforma. È descritto in questo MANTENERE . Ora puoi utilizzare direttamente l'estensione come parte della libreria standard di Kotlin senza definirla:

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

7

Sulla base di @ s1m0nw1 risposta eccellente ho apportato le seguenti modifiche.

  1. (0..n) implica inclusivo in Kotlin
  2. (Da 0 a n) implica l'esclusiva in Kotlin
  3. Utilizzare un oggetto singleton per l'istanza casuale (facoltativo)

Codice:

private object RandomRangeSingleton : Random()

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

Caso di prova:

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

Esempi casuali nell'intervallo [1, 10]

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

o utilizzando Java Random

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

1
La tua prima risposta mi piace di più. È un one-liner perfetto che non richiede di scrivere alcuna funzione di estensione
Alex Semeniuk,

4

Kotlin> = 1.3, supporto multipiattaforma per Random

A partire dalla 1.3, la libreria standard ha fornito supporto multipiattaforma per randoms, vedi questa risposta.

Kotlin <1.3 su JavaScript

Se stai lavorando con Kotlin JavaScript e non hai accesso a java.util.Random, funzionerà quanto segue:

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

Usato così:

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

4

Un altro modo di implementare la risposta di s1m0nw1 sarebbe accedervi attraverso una variabile. Non è più efficiente, ma ti evita di dover digitare ().

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

E ora è possibile accedervi come tale

(1..10).random

3

In Kotlin 1.3 puoi farlo come piace

val number = Random.nextInt(limit)

2

Non esiste un metodo standard che lo faccia ma puoi facilmente crearne uno tuo usando Math.random()o la classe java.util.Random. Ecco un esempio usando il Math.random()metodo:

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

Questo è un output di esempio:

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

2

La libreria standard Kotlin non fornisce l'API del generatore di numeri casuali. Se non fai parte di un progetto multipiattaforma, è meglio utilizzare l'API della piattaforma (tutte le altre risposte alla domanda parlano di questa soluzione) .

Ma se ti trovi in ​​un contesto multipiattaforma, la soluzione migliore è implementare random da solo in kotlin puro per condividere lo stesso generatore di numeri casuali tra piattaforme. È più semplice per sviluppatori e test.

Per rispondere a questo problema nel mio progetto personale, implemento un puro generatore congruenziale lineare Kotlin . LCG è l'algoritmo utilizzato da java.util.Random. Segui questo link se vuoi usarlo: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Il mio scopo di implementazione nextInt(range: IntRange)per te;).

Abbi cura del mio scopo, LCG è buono per la maggior parte dei casi d'uso (simulazione, giochi, ecc ...) ma non è adatto per l'uso crittografico a causa della prevedibilità di questo metodo.


Preferirei fare affidamento su un codice specifico della piattaforma piuttosto che creare il mio algoritmo casuale. Questo mi ricorda un po 'il codice per java.util.Random, ma non corrisponde completamente.
Simon Forsberg,

2

Se i numeri che si desidera scegliere non sono consecutivi, è possibile utilizzare random().

Uso:

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

Restituisce uno dei numeri presenti nell'elenco.



2

Utilizzando una funzione di livello superiore, puoi ottenere esattamente la stessa sintassi della chiamata di Ruby (come desideri):

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

Uso:

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

1

Innanzitutto, hai bisogno di un RNG. In Kotlin è attualmente necessario utilizzare quelli specifici della piattaforma (non esiste un Kotlin incorporato in uno). Per la JVM lo è java.util.Random. Dovrai crearne un'istanza e quindi chiamare random.nextInt(n).


1

Per ottenere un numero Int casuale in Kotlin utilizzare il seguente metodo :

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

Spero che questo ti aiuti.


0

È possibile creare una funzione di estensione:

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

Valore float rotondo:

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

Metodo di utilizzo:

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

Produzione:

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


0

Codice sorgente completo. Può controllare se sono consentiti duplicati.

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

Ogni volta che c'è una situazione in cui vuoi generare un indirizzo chiave o mac che è un numero esadecimale con cifre basate sulla domanda dell'utente e che anche usando Android e Kotlin, allora il mio codice qui sotto ti aiuta a:

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

-1

essere super duper))

 fun rnd_int(min: Int, max: Int): Int {
        var max = max
        max -= min
        return (Math.random() * ++max).toInt() + min
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.