Wie kann ich in Kotlin eine Zufallszahl bekommen?

151

Eine generische Methode, die eine zufällige Ganzzahl zwischen zwei Parametern zurückgeben kann, wie es Ruby tut rand(0..n).

Irgendein Vorschlag?

Yago Azedias
quelle

Antworten:

373

Mein Vorschlag wäre eine Erweiterungsfunktion in IntRange , um solche Zufälle zu erstellen:(0..10).random()

TL; DR Kotlin> = 1,3, ein Zufall für alle Plattformen

Ab 1.3 verfügt Kotlin über einen eigenen plattformübergreifenden Zufallsgenerator. Es wird in diesem KEEP beschrieben . Die unten beschriebene Erweiterung ist jetzt Teil der Kotlin-Standardbibliothek. Verwenden Sie sie einfach folgendermaßen:

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

Kotlin <1.3

Vor 1.3 verwenden wir auf der JVM Randomoder auch ThreadLocalRandomwenn wir auf JDK> 1.6 sind.

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

So verwendet:

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

Wenn Sie möchten, dass die Funktion nur zurückgegeben wird 1, 2, ..., 9( 10nicht enthalten), verwenden Sie einen Bereich mit until:

(0 until 10).random()

Wenn Sie mit JDK> 1.6 arbeiten, verwenden Sie ThreadLocalRandom.current()anstelle von Random().

KotlinJs und andere Variationen

Informationen zu Kotlinjs und anderen Anwendungsfällen, deren Verwendung nicht zulässig ist java.util.Random, finden Sie in dieser Alternative .

In dieser Antwort finden Sie auch Variationen meines Vorschlags. Es enthält auch eine Erweiterungsfunktion für zufällige Chars.

s1m0nw1
quelle
Ich nehme an, dies verwendet auch Java java.util.Random?
Simon Forsberg
@ SimonForsberg In der Tat. Ich habe eine weitere Antwort hinzugefügt, die nicht davon Gebrauch macht: stackoverflow.com/a/49507413/8073652
s1m0nw1
Es gibt auch einen Vorschlag hier, einen kryptografisch sicheren Pseudozufallszahlengenerator (CSPRNG) hier hinzuzufügen: github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh
41

Generieren Sie eine zufällige Ganzzahl zwischen from(einschließlich) und to(exklusiv)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}
Magnus
quelle
1
Wenn Sie ein paar zufällige IntZufälle erhalten möchten , können Sie stattdessen Random # int (Größe, von, bis) in Java-8 verwenden .
Holi-Java
3
Diese Lösung funktioniert nicht mit Javascript / Native Kotlin. Vielleicht könnte es cool sein, eine allgemeinere Methode zu entwickeln, um dies zu tun. :)
Valentin Michalak
@ ValentinMichalak können Sie dieses versuchen: stackoverflow.com/a/49507413/8073652
s1m0nw1
31

Ab Kotlin 1.2 können Sie schreiben:

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

Seien Sie sich nur bewusst, dass es ein großes O (n) ist, aber für eine kleine Liste (insbesondere mit eindeutigen Werten) ist es in Ordnung: D.

Mutexkid
quelle
Dieser ist nützlich für Kotlin-native
Benutzer3471194
11

Sie können eine Erweiterungsfunktion erstellen java.util.Random.nextInt(int), die IntRangeder Intfür ihre Bindung ähnlich ist, jedoch eine anstelle einer :

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

Sie können dies jetzt mit jeder RandomInstanz verwenden:

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

Wenn Sie keine eigene RandomInstanz verwalten müssen, können Sie eine praktische Methode definieren, indem Sie beispielsweise Folgendes verwenden ThreadLocalRandom.current():

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

Jetzt können Sie wie in Ruby eine zufällige Ganzzahl erhalten, ohne zuvor selbst eine RandomInstanz deklarieren zu müssen :

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

Mögliche Variation zu meiner anderen Antwort für zufällige Zeichen

Um zufällige Chars zu erhalten, können Sie eine Erweiterungsfunktion wie diese definieren

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

Wenn Sie mit JDK> 1.6 arbeiten, verwenden Sie ThreadLocalRandom.current() anstelle von Random().

Für Kotlinjs und andere Anwendungsfälle, deren Verwendung nicht zulässig ist java.util.Random, hilft diese Antwort .

Kotlin> = 1.3 Multiplattform-Unterstützung für Random

Ab 1.3 verfügt Kotlin über einen eigenen Multiplattform-Zufallsgenerator. Es wird in diesem KEEP beschrieben . Sie können die Erweiterung jetzt direkt als Teil der Kotlin-Standardbibliothek verwenden, ohne sie zu definieren:

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

Aufbauend auf @ s1m0nw1 ausgezeichnete Antwort Ich habe die folgenden Änderungen vorgenommen.

  1. (0..n) impliziert in Kotlin inklusive
  2. (0 bis n) impliziert exklusiv in Kotlin
  3. Verwenden Sie ein Singleton-Objekt für die Zufallsinstanz (optional).

Code:

private object RandomRangeSingleton : Random()

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

Testfall:

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
quelle
5

Beispiele zufällig im Bereich [1, 10]

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

oder mit Java Random

val random2 = Random().nextInt(10) + 1
Andrey
quelle
1
Deine erste Antwort gefällt mir am besten. Es ist ein perfekter Einzeiler, der keine Erweiterungsfunktionen schreiben muss
Alex Semeniuk
4

Kotlin> = 1.3, Multiplattform-Unterstützung für Random

Ab 1.3 bietet die Standardbibliothek Unterstützung für mehrere Plattformen, siehe diese Antwort.

Kotlin <1.3 auf JavaScript

Wenn Sie mit Kotlin JavaScript arbeiten und keinen Zugriff darauf haben java.util.Random, funktioniert Folgendes:

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

So verwendet:

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

Eine andere Möglichkeit, die Antwort von s1m0nw1 zu implementieren, besteht darin, über eine Variable darauf zuzugreifen. Nicht, dass es effizienter wäre, aber es erspart Ihnen die Eingabe von ().

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

Und jetzt kann als solches darauf zugegriffen werden

(1..10).random
Quinn
quelle
2

Es gibt keine Standardmethode, die dies tut, aber Sie können ganz einfach Ihre eigene Methode entweder mit Math.random()oder mit der Klasse erstellen java.util.Random. Hier ist ein Beispiel mit der Math.random()Methode:

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

Dies ist eine Beispielausgabe:

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

Die Kotlin-Standardbibliothek bietet keine Zufallszahlengenerator-API. Wenn Sie nicht in einem Multiplattform-Projekt sind, ist es besser, die Plattform-API zu verwenden (alle anderen Antworten auf die Frage sprechen von dieser Lösung) .

Wenn Sie sich jedoch in einem Multiplattform-Kontext befinden, besteht die beste Lösung darin, Random selbst in reinem Kotlin zu implementieren, um denselben Zufallszahlengenerator zwischen Plattformen zu teilen. Es ist einfacher für Entwickler und Tests.

Um dieses Problem in meinem persönlichen Projekt zu beantworten, implementiere ich einen reinen Kotlin Linear Congruential Generator . LCG ist der von java.util.Random. Folgen Sie diesem Link, wenn Sie ihn verwenden möchten: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Mein Implementierungszweck nextInt(range: IntRange)für Sie;).

Achten Sie auf meinen Zweck. LCG eignet sich für die meisten Anwendungsfälle (Simulation, Spiele usw.) , ist jedoch aufgrund der Vorhersagbarkeit dieser Methode nicht für die kryptografische Verwendung geeignet.

Valentin Michalak
quelle
Ich würde mich lieber auf plattformspezifischen Code verlassen, als meinen eigenen Zufallsalgorithmus zu erstellen. Dies erinnert mich ein wenig an den Code für java.util.Random, aber er stimmt nicht vollständig überein.
Simon Forsberg
2

In Kotlin 1.3 können Sie es so machen

val number = Random.nextInt(limit)
abweichend
quelle
2

Wenn die Nummern, aus denen Sie auswählen möchten, nicht fortlaufend sind, können Sie sie verwenden random().

Verwendung:

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

Gibt eine der Nummern zurück, die in der Liste enthalten sind.

Willi Mentzel
quelle
2

Sie müssen keine benutzerdefinierten Erweiterungsfunktionen mehr verwenden. IntRange verfügt jetzt über eine sofort einsatzbereiterandom() Erweiterungsfunktion.

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

Mit einer Funktion der obersten Ebene können Sie genau die gleiche Aufrufsyntax wie in Ruby erzielen (wie Sie möchten):

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

Verwendung:

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

Zunächst benötigen Sie ein RNG. In Kotlin müssen Sie derzeit die plattformspezifischen verwenden (es ist kein Kotlin in einem integriert). Für die JVM ist es java.util.Random. Sie müssen eine Instanz davon erstellen und dann aufrufen random.nextInt(n).

Mibac
quelle
1

Um eine zufällige Int-Zahl in Kotlin zu erhalten, verwenden Sie die folgende Methode :

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

Hoffe das hilft.

Andy Fedoroff
quelle
0

Sie können eine Erweiterungsfunktion erstellen:

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

Round Float-Wert:

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

Verwendung der Methode:

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

Ausgabe:

Wert: 0,0 Wert: 0,1 Wert: 0,2 Wert: 0,3 Wert: 0,4 Wert: 0,5 Wert: 0,6 Wert: 0,7 Wert: 0,8 Wert: 0,9 Wert: 1,0

rodrigosimoesrosa
quelle
0

Vollständiger Quellcode. Kann steuern, ob Duplikate zulässig sind.

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
quelle
0

Wann immer es eine Situation gibt, in der Sie eine Schlüssel- oder Mac-Adresse generieren möchten, bei der es sich um eine hexadezimale Zahl mit Ziffern handelt, die auf der Benutzeranforderung basieren, und dies auch unter Verwendung von Android und Kotlin, hilft Ihnen mein unten stehender Code:

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
quelle
-1

super duper sein))

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