How can I get a random number in Kotlin?

Viewed 199215

A generic method that can return a random integer between 2 parameters like ruby does with rand(0..n).

Any suggestion?

23 Answers

In Kotlin SDK >=1.3 you can do it like

import kotlin.random.Random

val number = Random.nextInt(limit)

Building off of @s1m0nw1 excellent answer I made the following changes.

  1. (0..n) implies inclusive in Kotlin
  2. (0 until n) implies exclusive in Kotlin
  3. Use a singleton object for the Random instance (optional)

Code:

private object RandomRangeSingleton : Random()

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

Test Case:

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

Examples random in the range [1, 10]

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

or utilizing Java Random

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

Another way of implementing s1m0nw1's answer would be to access it through a variable. Not that its any more efficient but it saves you from having to type ().

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

And now it can be accessed as such

(1..10).random

No need to use custom extension functions anymore. IntRange has a random() extension function out-of-the-box now.

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

Kotlin standard lib doesn't provide Random Number Generator API. If you aren't in a multiplatform project, it's better to use the platform api (all the others answers of the question talk about this solution).

But if you are in a multiplatform context, the best solution is to implement random by yourself in pure kotlin for share the same random number generator between platforms. It's more simple for dev and testing.

To answer to this problem in my personal project, i implement a pure Kotlin Linear Congruential Generator. LCG is the algorithm used by java.util.Random. Follow this link if you want to use it : https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

My implementation purpose nextInt(range: IntRange) for you ;).

Take care about my purpose, LCG is good for most of the use cases (simulation, games, etc...) but is not suitable for cryptographically usage because of the predictability of this method.

To get a random Int number in Kotlin use the following method:

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

Hope this helps.

Below in Kotlin worked well for me:

(fromNumber.rangeTo(toNumber)).random()

Range of the numbers starts with variable fromNumber and ends with variable toNumber. fromNumber and toNumber will also be included in the random numbers generated out of this.

You could create an extension function:

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 value:

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

Method's usage:

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

Output:

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

Full source code. Can control whether duplicates are allowed.

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

Whenever there is a situation where you want to generate key or mac address which is hexadecimal number having digits based on user demand, and that too using android and kotlin, then you my below code helps you:

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

Here is a straightforward solution in Kotlin, which also works on KMM:

fun IntRange.rand(): Int =
    Random(Clock.System.now().toEpochMilliseconds()).nextInt(first, last)

Seed is needed for the different random number on each run. You can also do the same for the LongRange.

to be super duper ))

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