How can I get a random number in Kotlin?

后端 未结 22 1513
一个人的身影
一个人的身影 2020-12-12 15:02

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

Any suggestion?

相关标签:
22条回答
  • 2020-12-12 16:05

    Examples random in the range [1, 10]

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

    or utilizing Java Random

    val random2 = Random().nextInt(10) + 1
    
    0 讨论(0)
  • 2020-12-12 16:06

    You can create an extension function similar to java.util.Random.nextInt(int) but one that takes an IntRange instead of an Int for its bound:

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

    You can now use this with any Random instance:

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

    If you don't want to have to manage your own Random instance then you can define a convenience method using, for example, ThreadLocalRandom.current():

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

    Now you can get a random integer as you would in Ruby without having to first declare a Random instance yourself:

    rand(5..9) // returns 5, 6, 7, or 8
    
    0 讨论(0)
  • 2020-12-12 16:06

    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.

    0 讨论(0)
  • 2020-12-12 16:06

    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

    0 讨论(0)
提交回复
热议问题