Bagaimana saya bisa mendapatkan nomor acak di Kotlin?

151

Metode generik yang dapat mengembalikan bilangan bulat acak antara 2 parameter seperti halnya ruby rand(0..n).

Ada saran?

Yago Azedias
sumber

Jawaban:

373

Saran saya akan menjadi fungsi ekstensi di IntRange untuk membuat tebusan seperti ini:(0..10).random()

TL; DR Kotlin> = 1.3, satu Acak untuk semua platform

Pada 1.3, Kotlin hadir dengan generator Acak multi-platform sendiri. Ini dijelaskan dalam KEEP ini . Ekstensi yang dijelaskan di bawah sekarang menjadi bagian dari perpustakaan standar Kotlin , cukup gunakan seperti ini:

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

Kotlin <1.3

Sebelum 1.3, pada JVM kita menggunakan Randomatau bahkan ThreadLocalRandomjika kita menggunakan JDK> 1.6.

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

Digunakan seperti ini:

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

Jika Anda ingin fungsi hanya kembali 1, 2, ..., 9( 10tidak termasuk), gunakan rentang yang dibangun dengan until:

(0 until 10).random()

Jika Anda bekerja dengan JDK> 1.6, gunakan ThreadLocalRandom.current()sebagai ganti Random().

Kotlin dan variasi lainnya

Untuk kotlinjs dan kasus penggunaan lainnya yang tidak memungkinkan penggunaan java.util.Random, lihat alternatif ini .

Juga, lihat jawaban ini untuk variasi saran saya. Ini juga mencakup fungsi ekstensi untuk Chars acak .

s1m0nw1
sumber
Saya menganggap ini juga menggunakan Java java.util.Random?
Simon Forsberg
@SimonForsberg Memang. Saya menambahkan jawaban lain yang tidak memanfaatkannya: stackoverflow.com/a/49507413/8073652
s1m0nw1
Ada juga proposal di sini untuk menambahkan Pseudo-Random Number Generator (CSPRNG) Cryptographically Secure di sini: github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh
41

Hasilkan bilangan bulat acak antara from(inklusif) dan to(eksklusif)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}
Magnus
sumber
1
Jika Anda ingin mendapatkan beberapa Ints acak acak , Anda bisa menggunakan Random # int (size, from, to) sebagai gantinya di java-8 .
holi-java
3
Solusi ini tidak berfungsi pada Javascript / Asli Kotlin. Mungkin keren untuk membuat metode yang lebih umum untuk melakukan ini. :)
Valentin Michalak
@ValentinMichalak Anda dapat mencoba yang ini: stackoverflow.com/a/49507413/8073652
s1m0nw1
31

Pada kotlin 1.2, Anda dapat menulis:

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

Sadarilah itu besar O (n), tetapi untuk daftar kecil (terutama nilai-nilai unik) tidak apa-apa: D

mutexkid
sumber
yang satu ini berguna untuk kotlin-native
user3471194
11

Anda dapat membuat fungsi ekstensi yang mirip dengan java.util.Random.nextInt(int)tetapi yang mengambil IntRangealih - alih Intuntuk terikat:

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

Anda sekarang dapat menggunakan ini dengan Randomcontoh apa pun :

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

Jika Anda tidak ingin harus mengatur Randominstance Anda sendiri maka Anda dapat menentukan metode kenyamanan menggunakan, misalnya ThreadLocalRandom.current(),:

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

Sekarang Anda bisa mendapatkan bilangan bulat acak seperti di Ruby tanpa harus terlebih dahulu mendeklarasikan Randominstance:

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

Kemungkinan Variasi untuk jawaban saya yang lain untuk karakter acak

Untuk mendapatkan Chars acak , Anda dapat menentukan fungsi ekstensi seperti ini

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

Jika Anda bekerja dengan JDK> 1.6, gunakan ThreadLocalRandom.current() sebagai gantiRandom() .

Untuk kotlinjs dan kasus penggunaan lainnya yang tidak memungkinkan penggunaan java.util.Random , jawaban ini akan membantu.

Kotlin> = 1.3 dukungan multi platform untuk Acak

Pada 1.3, Kotlin hadir dengan generator Acak multiplatform sendiri. Ini dijelaskan dalam KEEP ini . Anda sekarang dapat langsung menggunakan ekstensi sebagai bagian dari perpustakaan standar Kotlin tanpa mendefinisikannya:

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

Membangun dari @ s1m0nw1 jawaban yang sangat baik saya membuat perubahan berikut.

  1. (0..n) menyiratkan inklusif di Kotlin
  2. (0 hingga n) menyiratkan eksklusif di Kotlin
  3. Gunakan objek tunggal untuk contoh acak (opsional)

Kode:

private object RandomRangeSingleton : Random()

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

Kasus cobaan:

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

Contoh acak dalam kisaran [1, 10]

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

atau memanfaatkan Java Random

val random2 = Random().nextInt(10) + 1
Andrey
sumber
1
Jawaban pertama Anda yang paling saya sukai. Ini adalah one-liner sempurna yang tidak perlu untuk menulis fungsi ekstensi apa pun
Alex Semeniuk
4

Kotlin> = 1.3, dukungan multi platform untuk Acak

Pada 1.3, perpustakaan standar menyediakan dukungan multi-platform untuk tebusan, lihat jawaban ini .

Kotlin <1.3 pada JavaScript

Jika Anda bekerja dengan Kotlin JavaScript dan tidak memiliki akses ke java.util.Random, yang berikut ini akan berfungsi:

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

Digunakan seperti ini:

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

Cara lain untuk mengimplementasikan jawaban s1m0nw1 adalah dengan mengaksesnya melalui variabel. Bukan berarti ini lebih efisien tetapi menghemat Anda dari keharusan mengetik ().

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

Dan sekarang dapat diakses seperti itu

(1..10).random
Quinn
sumber
3

Di Kotlin 1.3 Anda bisa melakukannya

val number = Random.nextInt(limit)
menyimpang
sumber
2

Tidak ada metode standar yang melakukan ini tetapi Anda dapat dengan mudah membuat sendiri menggunakan salah satu Math.random()atau kelas java.util.Random. Berikut ini adalah contoh menggunakan Math.random()metode ini:

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

Ini adalah contoh output:

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

Lib standar Kotlin tidak menyediakan API Penghasil Angka Acak. Jika Anda tidak berada dalam proyek multi platform, lebih baik menggunakan api platform (semua yang lain menjawab pertanyaan, bicarakan solusi ini) .

Tetapi jika Anda berada dalam konteks multi platform, solusi terbaik adalah menerapkan sendiri secara acak di kotlin murni untuk berbagi generator angka acak yang sama antar platform. Ini lebih mudah untuk dev dan pengujian.

Untuk menjawab masalah ini dalam proyek pribadi saya, saya menerapkan Generator Congruential Kotlin Linear murni . LCG adalah algoritma yang digunakan oleh java.util.Random. Ikuti tautan ini jika Anda ingin menggunakannya: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Tujuan implementasi saya nextInt(range: IntRange)untuk Anda;).

Jaga tujuan saya, LCG baik untuk sebagian besar kasus penggunaan (simulasi, game, dll ...) tetapi tidak cocok untuk penggunaan kriptografis karena dapat diprediksi metode ini.

Valentin Michalak
sumber
Saya lebih suka mengandalkan kode spesifik platform daripada membuat algoritma acak saya sendiri. Ini sedikit mengingatkan saya tentang kode untuk java.util.Random, tetapi tidak sepenuhnya cocok.
Simon Forsberg
2

Jika angka yang ingin Anda pilih tidak berurutan, Anda bisa menggunakan random().

Pemakaian:

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

Mengembalikan salah satu angka yang ada dalam daftar.

Willi Mentzel
sumber
2

Tidak perlu menggunakan fungsi ekstensi khusus lagi. IntRange memiliki random()fungsi ekstensi di luar kotak sekarang.

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

Menggunakan fungsi tingkat atas, Anda dapat mencapai sintaks panggilan yang sama persis seperti di Ruby (seperti yang Anda inginkan):

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

Pemakaian:

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

Pertama, Anda membutuhkan RNG. Di Kotlin saat ini Anda harus menggunakan platform spesifik (tidak ada Kotlin yang dibangun dalam satu). Untuk JVM itu java.util.Random. Anda harus membuat instance dan kemudian menelepon random.nextInt(n).

Mibac
sumber
1

Untuk mendapatkan nomor Int acak di Kotlin gunakan metode berikut :

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

Semoga ini membantu.

Andy Fedoroff
sumber
0

Anda dapat membuat fungsi ekstensi:

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

Nilai Float bulat:

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

Penggunaan metode:

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

Keluaran:

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

rodrigosimoesrosa
sumber
0

Kode sumber lengkap. Dapat mengontrol apakah duplikat diizinkan.

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

Setiap kali ada situasi di mana Anda ingin menghasilkan kunci atau alamat mac yang nomor heksadesimal memiliki digit berdasarkan permintaan pengguna, dan itu juga menggunakan android dan kotlin, maka Anda kode saya di bawah ini membantu Anda:

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

menjadi super duper))

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