如何在Kotlin中获得随机数?


151

可以返回2个参数之间的随机整数的通用方法,例如ruby与rand(0..n)

有什么建议吗?

Answers:


373

我的建议是一个扩展的功能IntRange创建这样的随机量:(0..10).random()

TL; DR Kotlin> = 1.3,适用于所有平台,随机

从1.3开始,Kotlin带有自己的多平台随机数发生器。在此KEEP中对此进行了描述。下面描述的扩展现在是Kotlin标准库的一部分,只需像这样使用它:

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

科特林<1.3

在1.3之前,我们在JVM上使用Random,甚至ThreadLocalRandom在JDK> 1.6上也是如此。

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

像这样使用:

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

如果您只希望函数返回1, 2, ..., 910不包括在内),请使用以下构造的范围until

(0 until 10).random()

如果您使用的是JDK> 1.6,请使用ThreadLocalRandom.current()代替Random()

KotlinJs和其他变体

对于不允许使用的kotlinjs和其他用例java.util.Random,请参见此替代方法

另外,请参阅此答案以了解我的建议。它还包括用于random Char的扩展功能。


我认为这也使用Java的java.util.Random
西蒙·佛斯伯格

@SimonForsberg确实。我添加了另一个未使用的答案:stackoverflow.com/a/49507413/8073652
s1m0nw1

这里还有一个建议在此处添加加密安全的伪随机数生成器(CSPRNG):github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh '19

41

生成介于from(包含)和to(不含)之间的随机整数

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}

1
如果要获取两个远程随机数Int,可以在Java-8中使用Random#int(size,from,to)
holi-java

3
此解决方案不适用于Javascript / Native Kotlin。也许可以采用更通用的方法来做到这一点。:)
Valentin Michalak '18

@ValentinMichalak,您可以尝试以下方法:stackoverflow.com/a/49507413/8073652
s1m0nw1

31

从kotlin 1.2开始,您可以编写:

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

只是要知道它是大O(n),但对于一小列表(尤其是唯一值)来说,它就可以了:D


这对kotlin本机很有用
user3471194 18-10-28

11

您可以创建类似于的扩展函数java.util.Random.nextInt(int)但其边界需要一个IntRange而不是一个Int

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

现在,您可以将其用于任何Random实例:

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

如果您不想管理自己的Random实例,则可以使用以下方法定义一种便捷方法ThreadLocalRandom.current()

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

现在,您可以像在Ruby中那样获得一个随机整数,而不必先声明一个Random实例:

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

10

我对随机字符的其他答案的可能变化

为了获得random Char,您可以定义一个扩展函数,如下所示

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

如果您使用的是JDK> 1.6,请使用ThreadLocalRandom.current() 代替Random()

对于kotlinjs和其他不允许使用的用例java.util.Random此答案将有所帮助。

Kotlin> = 1.3对Random的多平台支持

从1.3开始,Kotlin附带了自己的多平台随机数生成器。在此KEEP中对此进行了描述。现在,您无需定义扩展即可将扩展直接用作Kotlin标准库的一部分:

('a'..'b').random()

7

基于@ s1m0nw1的出色答案,我进行了以下更改。

  1. (0..n)在Kotlin中包含
  2. (0到n)表示科特林独占
  3. 对Random实例使用单例对象(可选)

码:

private object RandomRangeSingleton : Random()

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

测试用例:

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

5

示例范围为[1,10]的随机

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

或利用Java Random

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

1
您最喜欢的第一个答案。这是一个完美的单行代码,不需要编写任何扩展功能
Alex Semeniuk

4

Kotlin> = 1.3,对Random的多平台支持

从1.3版本开始,标准库提供的随机量多平台支持,看到这个答案。

Kotlin <1.3(基于JavaScript)

如果您使用Kotlin JavaScript并且没有访问权限java.util.Random,则可以使用以下命令:

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

像这样使用:

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

4

实现s1m0nw1答案的另一种方法是通过变量访问它。并不是说它更有效,但是它使您不必键入()。

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

现在可以这样访问

(1..10).random

3

在Kotlin 1.3中,您可以像

val number = Random.nextInt(limit)

2

没有标准方法可以执行此操作,但是您可以使用Math.random()或类轻松创建自己的方法java.util.Random。这是使用该Math.random()方法的示例:

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

这是一个示例输出:

[9, 8, 1, 7, 5, 6, 9, 8, 1, 9]
[5, 8, 9, 7, 6, 6, 8, 6, 7, 9]

2

Kotlin标准库不提供随机数生成器API。如果您不在多平台项目中,则最好使用平台api (问题的所有其他答案都讨论此解决方案)

但是,如果您处于多平台环境中,最好的解决方案是在纯Kotlin中自己实现随机,以在平台之间共享相同的随机数生成器。开发和测试更加简单。

为了在我的个人项目中回答这个问题,我实现了一个纯Kotlin 线性同余生成器。LCG是的算法java.util.Random。如果要使用它,遵循此链接:https : //gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

nextInt(range: IntRange)为您实现的目的;)。

请注意我的目的,LCG适用于大多数用例(模拟,游戏等),但由于此方法的可预测性,因此不适合密码使用。


我宁愿依赖于平台特定的代码,也不愿自己制定随机算法。这让我想起了java.util.Random的代码,但是它并不完全匹配。
西蒙·佛斯伯格



2

使用顶级功能,您可以实现与Ruby中完全相同的调用语法(如您所愿):

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

用法:

rand(1, 3) // returns either 1, 2 or 3

1

首先,您需要一个RNG。在Kotlin中,您当前需要使用特定于平台的工具(没有内置的Kotlin)。对于JVM,它是java.util.Random。您需要为其创建一个实例,然后调用random.nextInt(n)


1

要在Kotlin中获得随机的Int数,请使用以下方法

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

希望这可以帮助。


0

您可以创建扩展功能:

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

来回浮动值:

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

方法的用法:

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

输出:

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


0

完整的源代码。可以控制是否允许重复。

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

0

每当有需要生成密钥或mac地址(使用基于用户需求的数字为十六进制的数字)的情况时,以及使用android和kotlin的情况时,我的以下代码都会为您提供帮助:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.