我怎么能在Kotlin得到一个随机数?

一个泛型方法,可以返回两个参数之间的随机整数,就像ruby对rand(0..n)所做的那样。

任何建议吗?

213258 次浏览

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

from(包含)和to(不包含)之间生成一个随机整数

import java.util.Random


val random = Random()


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

没有标准方法可以做到这一点,但你可以使用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]

我的建议是在IntRange上创建一个扩展函数来创建像这样的随机:(0..10).random()

TL;DR Kotlin >= 1.3,一个随机的所有平台

在1.3版本中,Kotlin自带多平台随机生成器。它在保持中描述。下面描述的扩展现在是Kotlin标准库的一部分,简单地像这样使用它:

val rnds = (0..10).random() // generated random from 0 to 10 included

芬兰湾的科特林& lt;1.3

在1.3之前,在JVM上我们使用Random,如果我们在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, ..., 9(不包括10),使用由until构造的范围:

(0 until 10).random()

如果你正在使用JDK >1.6,使用ThreadLocalRandom.current()代替Random()

KotlinJs和其他变体

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

另外,请参见this 回答以获得我的建议的变体。它还包括一个用于随机__abc的扩展函数。

你可以创建一个类似于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, 8, or 9

如果你不想管理自己的Random实例,那么你可以定义一个方便的方法,例如使用ThreadLocalRandom.current():

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

现在你可以像在Ruby中一样获得一个随机整数,而无需自己首先声明Random实例:

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

基于@s1m0nw1的优秀答案,我做了以下更改。

  1. (0..n)在Kotlin中表示包含
  2. (0到n)在Kotlin中表示独占
  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())
}
)
}

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

为了获得随机的__abc,你可以像这样定义一个扩展函数

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,请使用__abc2而不是Random()

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

Kotlin >= 1.3多平台随机支持

在1.3版本中,Kotlin自带多平台随机生成器。它在保持中描述。你现在可以直接使用扩展作为Kotlin标准库的一部分,而不需要定义它:

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

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

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

用法:

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

如果你想从中选择的数字不是连续的,你可以使用random()

用法:

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

返回列表中的一个数字。

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

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

为了在我的个人项目中回答这个问题,我实现了一个纯Kotlin 线性同余发生器。LCG是java.util.Random使用的算法。如果你想使用它,请点击以下链接: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4 < / p >

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

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

从kotlin 1.2开始,您可以这样写:

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

只要注意它是大O(n),但对于一个小列表(特别是唯一值),它是可以的:D

Kotlin >= 1.3,多平台随机支持

从1.3开始,标准库提供了随机的多平台支持,参见 answer。

芬兰湾的科特林& lt;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()

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

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

或者使用Java Random

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

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

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

现在它可以被这样访问

(1..10).random

在Kotlin SDK >=1.3中,你可以这样做

import kotlin.random.Random


val number = Random.nextInt(limit)

成为超级高手))

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

不再需要使用自定义扩展函数。IntRange现在有一个开箱即用的random()扩展函数。

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

要在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

希望这能有所帮助。

你可以创建一个扩展函数:

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

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

输出:

value: 0.0 value: 0.1 value: 0.2 value: 0.3 value: 0.4 value: 0.5 值:0.6值:0.7值:0.8值:0.9值:1.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("")
}
}
}

每当有一种情况,你想要生成密钥或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()
}

Kotlin中的以下内容对我来说效果很好:

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

数值范围以变量fromNumber开始,以变量toNumber结束。fromNumbertoNumber也将包含在由此生成的随机数中。

下面是Kotlin中的一个简单的解决方案,它也适用于KMM:

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

种子用于每次运行时不同的随机数。您也可以为LongRange做同样的事情。