Jak mogę otrzymać losową liczbę w Kotlinie?

151

Ogólna metoda, która może zwrócić losową liczbę całkowitą między 2 parametrami, tak jak robi to ruby rand(0..n).

Jakieś sugestie?

Yago Azedias
źródło

Odpowiedzi:

373

Moją sugestią byłaby funkcja rozszerzająca w IntRange do tworzenia takich losów:(0..10).random()

TL; DR Kotlin> = 1.3, jeden losowy dla wszystkich platform

Od 1.3 Kotlin jest wyposażony we własny wieloplatformowy generator losowy. Jest to opisane w tym ZACHOWAJ . Opisane poniżej rozszerzenie jest teraz częścią standardowej biblioteki Kotlin , po prostu użyj go w następujący sposób:

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

Kotlin <1,3

Przed 1.3 w JVM używamy Randomlub nawet ThreadLocalRandomjeśli jesteśmy na JDK> 1.6.

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

Używane w ten sposób:

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

Jeśli chcesz, aby funkcja zwracała tylko 1, 2, ..., 9( 10nie uwzględniono), użyj zakresu skonstruowanego za pomocą until:

(0 until 10).random()

Jeśli pracujesz z JDK> 1.6, użyj ThreadLocalRandom.current()zamiast Random().

KotlinJs i inne odmiany

W przypadku kotlinjs i innych przypadków użycia, które nie pozwalają na użycie java.util.Random, zobacz tę alternatywę .

Zobacz również tę odpowiedź dla odmian mojej sugestii. Zawiera również funkcję rozszerzenia dla losowych Chars.

s1m0nw1
źródło
Zakładam, że to również używa Java java.util.Random?
Simon Forsberg
@SimonForsberg Rzeczywiście. Dodałem kolejną odpowiedź, która z niej nie korzysta: stackoverflow.com/a/49507413/8073652
s1m0nw1
Jest tu również propozycja dodania Cryptographically Secure Pseudo-Random Number Generator (CSPRNG) tutaj: github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh
41

Wygeneruj losową liczbę całkowitą z przedziału from(włącznie) i to(wyłącznie)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}
Magnus
źródło
1
Jeśli chcesz uzyskać kilka losowych Intznaków z zakresu, możesz użyć Random # int (size, from, to) zamiast w java-8 .
holi-java
3
To rozwiązanie nie działa na Javascript / Native Kotlin. Być może fajnie byłoby stworzyć bardziej ogólną metodę, aby to zrobić. :)
Valentin Michalak
@ValentinMichalak, możesz spróbować tego: stackoverflow.com/a/49507413/8073652
s1m0nw1
31

Od Kotlin 1.2 można napisać:

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

Tylko pamiętaj, że to duże O (n), ale dla małej listy (szczególnie unikalnych wartości) jest w porządku: D

mutexkid
źródło
ten jest przydatny dla kotlin-native
user3471194
11

Możesz utworzyć funkcję rozszerzającą podobną do java.util.Random.nextInt(int)tej, która przyjmuje IntRangezamiast an Intdla swojego powiązania:

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

Możesz teraz użyć tego z dowolną Randominstancją:

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

Jeśli nie chcesz zarządzać własną Randominstancją, możesz zdefiniować wygodną metodę, używając na przykład ThreadLocalRandom.current():

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

Teraz możesz otrzymać losową liczbę całkowitą, tak jak w Rubim, bez konieczności wcześniejszego deklarowania Randominstancji:

rand(5..9) // returns 5, 6, 7, or 8
mfulton26
źródło
10

Możliwa odmiana mojej innej odpowiedzi dla losowych znaków

Aby uzyskać losowe wartości Chars, możesz zdefiniować taką funkcję rozszerzającą

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

Jeśli pracujesz z JDK> 1.6, użyj ThreadLocalRandom.current() zamiast Random().

W przypadku kotlinjs i innych przypadków użycia, które nie pozwalają na użycie java.util.Random, ta odpowiedź pomoże.

Kotlin> = 1.3 wsparcie dla wielu platform dla Random

Od 1.3 Kotlin jest wyposażony we własny wieloplatformowy generator losowy. Jest to opisane w tym ZACHOWAJ . Możesz teraz bezpośrednio używać rozszerzenia jako części standardowej biblioteki Kotlin bez definiowania go:

('a'..'b').random()
s1m0nw1
źródło
7

Opierając się na doskonałej odpowiedzi @ s1m0nw1 , wprowadziłem następujące zmiany.

  1. (0..n) implikuje włączenie w Kotlinie
  2. (0 do n) oznacza wyłączność w Kotlinie
  3. Użyj pojedynczego obiektu dla instancji Random (opcjonalnie)

Kod:

private object RandomRangeSingleton : Random()

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

Przypadek testowy:

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
źródło
5

Przykłady losowe w zakresie [1, 10]

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

lub wykorzystując Java Random

val random2 = Random().nextInt(10) + 1
Andrey
źródło
1
Twoja pierwsza odpowiedź podoba mi się najbardziej. To doskonała jednolinijka, która nie wymaga pisania żadnych funkcji rozszerzających
Alex Semeniuk
4

Kotlin> = 1.3, wieloplatformowa obsługa Random

Od wersji 1.3 biblioteka standardowa zapewnia obsługę wielu platform dla losowych danych, zobacz odpowiedź.

Kotlin <1.3 w JavaScript

Jeśli pracujesz z Kotlin JavaScript i nie masz do niego dostępu java.util.Random, zadziałają:

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

Używane w ten sposób:

// will return an `Int` between 0 and 10 (incl.)
(0..10).random()
s1m0nw1
źródło
4

Innym sposobem zaimplementowania odpowiedzi s1m0nw1 byłoby uzyskanie do niej dostępu poprzez zmienną. Nie oznacza to, że jest to bardziej wydajne, ale pozwala uniknąć konieczności wpisywania ().

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

A teraz można uzyskać do niego dostęp jako taki

(1..10).random
Quinn
źródło
3

W Kotlin 1.3 możesz to zrobić jak

val number = Random.nextInt(limit)
zboczeniec
źródło
2

Nie ma standardowej metody, która to robi, ale możesz łatwo utworzyć własną, używając jednej z nich Math.random()lub klasy java.util.Random. Oto przykład wykorzystujący Math.random()metodę:

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

Oto przykładowe dane wyjściowe:

[9, 8, 1, 7, 5, 6, 9, 8, 1, 9]
[5, 8, 9, 7, 6, 6, 8, 6, 7, 9]
Mahdi AlKhalaf
źródło
2

Biblioteka standardu Kotlin nie zapewnia interfejsu API generatora liczb losowych. Jeśli nie jesteś w projekcie wieloplatformowym, lepiej skorzystać z api platformy (wszystkie pozostałe odpowiedzi na pytanie mówią o tym rozwiązaniu) .

Ale jeśli pracujesz w kontekście wieloplatformowym, najlepszym rozwiązaniem jest samodzielne zaimplementowanie losowego w czystym kotlinie w celu współdzielenia tego samego generatora liczb losowych między platformami. Programowanie i testowanie jest prostsze.

Aby odpowiedzieć na ten problem w moim osobistym projekcie, wdrażam czysty liniowy generator kongruencyjny Kotlin . LCG to algorytm używany przez java.util.Random. Kliknij ten link, jeśli chcesz go użyć: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Mój cel realizacji nextInt(range: IntRange)dla Ciebie;).

Uważaj na mój cel, LCG jest dobre w większości przypadków użycia (symulacja, gry itp.), Ale nie nadaje się do użytku kryptograficznego ze względu na przewidywalność tej metody.

Valentin Michalak
źródło
Wolę polegać na kodzie specyficznym dla platformy niż tworzyć własny algorytm losowy. Przypomina mi to trochę o kodzie java.util.Random, ale nie do końca pasuje.
Simon Forsberg
2

Jeśli liczby, z których chcesz wybierać, nie są kolejnymi liczbami, możesz użyć random().

Stosowanie:

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

Zwraca jedną z liczb znajdujących się na liście.

Willi Mentzel
źródło
2

Nie ma już potrzeby korzystania z niestandardowych funkcji rozszerzeń. IntRange ma teraz random()funkcję rozszerzenia od razu po wyjęciu z pudełka.

val randomNumber = (0..10).random()
Willi Mentzel
źródło
2

Używając funkcji najwyższego poziomu, możesz osiągnąć dokładnie taką samą składnię wywołań jak w Rubim (jak chcesz):

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

Stosowanie:

rand(1, 3) // returns either 1, 2 or 3
Willi Mentzel
źródło
1

Najpierw potrzebujesz RNG. W Kotlinie obecnie musisz korzystać z platform specyficznych dla platformy (nie ma wbudowanego Kotlina). Dla JVM to java.util.Random. Musisz utworzyć jego instancję, a następnie zadzwonić random.nextInt(n).

Mibac
źródło
1

Aby uzyskać losową liczbę Int w Kotlinie, użyj następującej metody :

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

Mam nadzieję że to pomoże.

Andy Fedoroff
źródło
0

Możesz utworzyć funkcję rozszerzenia:

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

Wartość Round Float:

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

Zastosowanie metody:

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

Wynik:

Wartość: 0,0 Wartość: 0,1 Wartość: 0,2 Wartość: 0,3 Wartość: 0,4 Wartość: 0,5 Wartość: 0,6 Wartość: 0,7 Wartość: 0,8 Wartość: 0,9 Wartość: 1,0

rodrigosimoesrosa
źródło
0

Pełny kod źródłowy. Może kontrolować, czy dozwolone są duplikaty.

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
źródło
0

Ilekroć jest sytuacja, w której chcesz wygenerować klucz lub adres mac, który jest liczbą szesnastkową zawierającą cyfry na podstawie żądania użytkownika, a także przy użyciu Androida i Kotlin, mój poniższy kod pomoże ci:

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
źródło
-1

być super duperem))

 fun rnd_int(min: Int, max: Int): Int {
        var max = max
        max -= min
        return (Math.random() * ++max).toInt() + min
    }
Deomin Dmitriy
źródło