【问题标题】:How can I get a random number in Kotlin?如何在 Kotlin 中获取随机数?
【发布时间】:2018-01-22 21:54:00
【问题描述】:

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

有什么建议吗?

【问题讨论】:

    标签: random kotlin jvm


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      import java.util.Random
      
      val random = Random()
      
      fun rand(from: Int, to: Int) : Int {
          return random.nextInt(to - from) + from
      }
      

      【讨论】:

      【解决方案3】:

      没有执行此操作的标准方法,但您可以使用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]
      

      【讨论】:

        【解决方案4】:

        我的建议是在IntRange 上使用extension 函数来创建这样的随机数:(0..10).random()

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

        从 1.3 开始,Kotlin 自带了自己的多平台随机生成器。这在KEEP 中有描述。下面描述的扩展现在是part of the Kotlin standard library,只需像这样使用它:

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

        科特林

        在 1.3 之前,在 JVM 上我们使用 Random,如果我们在 JDK > 1.6 上,甚至使用 ThreadLocalRandom

        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 alternative

        另外,请参阅answer 了解我的建议的变体。它还包括随机Chars 的扩展功能。

        【讨论】:

        • 我假设这也使用了 Java 的 java.util.Random?
        • @SimonForsberg 确实如此。我添加了另一个没有使用它的答案:stackoverflow.com/a/49507413/8073652
        • 这里还有一个建议,在这里添加一个加密安全伪随机数生成器 (CSPRNG):github.com/Kotlin/KEEP/issues/184
        • val rnds = (0..10).random() 实际上生成 0 到 10,包括 100pl.kotl.in/1o8LyD1Dc
        • 虽然每次通话都返回相同的号码,但它可以工作
        【解决方案5】:

        您可以创建一个类似于java.util.Random.nextInt(int)extension function,但它的边界采用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
        

        【讨论】:

          【解决方案6】:

          基于@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())
                          }
                  )
              }
          

          【讨论】:

            【解决方案7】:

            我的other answer 随机字符的可能变化

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

            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 的用例,this answer 会有所帮助。

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

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

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

            【讨论】:

              【解决方案8】:

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

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

              用法:

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

              【讨论】:

                【解决方案9】:

                如果要选择的数字不连续,可以使用random()

                用法:

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

                返回列表中的数字之一。

                【讨论】:

                  【解决方案10】:

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

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

                  为了在我的个人项目中解决这个问题,我实现了一个纯 Kotlin Linear Congruential Generator。 LCG 是java.util.Random 使用的算法。如果您想使用它,请点击此链接: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

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

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

                  【讨论】:

                  • 我宁愿依赖特定于平台的代码,也不愿自己制作随机算法。这让我想起了一些关于 java.util.Random 的代码,但它并不完全匹配。
                  【解决方案11】:

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

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

                  请注意它的 O(n) 很大,但对于一个小列表(尤其是唯一值)来说没关系:D

                  【讨论】:

                  • 这个对kotlin-native很有用
                  【解决方案12】:

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

                  从 1.3 开始,标准库为随机数提供了多平台支持,请参阅 this 答案。

                  Kotlin

                  如果您使用 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()
                  

                  【讨论】:

                    【解决方案13】:

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

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

                    或使用 Java Random

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

                    【讨论】:

                    • 你的第一个回答我最喜欢。这是一个完美的单行代码,不需要编写任何扩展函数
                    • @AlexSemeniuk 请不要。 shuffled() 将返回一个列表。想象一下如果你通过(0..Integer.MAX_VALUE)会发生什么
                    • @deviant 好点。只是我有一个用例,我需要从集合中获取随机元素。
                    【解决方案14】:

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

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

                    现在可以这样访问了

                    (1..10).random
                    

                    【讨论】:

                      【解决方案15】:

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

                      import kotlin.random.Random
                      
                      val number = Random.nextInt(limit)
                      

                      【讨论】:

                        【解决方案16】:

                        成为超级骗子))

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

                        【讨论】:

                          【解决方案17】:

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

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

                          【讨论】:

                            【解决方案18】:

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

                            希望这会有所帮助。

                            【讨论】:

                              【解决方案19】:

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

                              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

                              【讨论】:

                                【解决方案20】:

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

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

                                【讨论】:

                                  【解决方案21】:

                                  当您想要生成密钥或 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()
                                  } 
                                  

                                  【讨论】:

                                    【解决方案22】:

                                    下面的 Kotlin 对我来说效果很好:

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

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

                                    【讨论】:

                                      猜你喜欢
                                      • 2023-03-30
                                      • 1970-01-01
                                      • 2012-04-12
                                      • 2010-09-16
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多