【问题标题】:Kotlin - Random numbers without repeatingKotlin - 不重复的随机数
【发布时间】:2021-08-02 18:10:01
【问题描述】:

我有一个问题,如何防止随机数重复。 顺便问一下,谁能给我解释一下如何对这些随机数进行排序?

override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView = findViewById<TextView>(R.id.textView)
        val button = findViewById<Button>(R.id.buttom)


        button.setOnClickListener {

            var liczba = List(6){Random.nextInt(1,69)}
            textView.text = liczba.toString()
        }
    }

【问题讨论】:

  • 您可以在列表中调用sorted 以获取排序后的版本(如果您想就地排序,可以在MutableList 上调用sort
  • 您还可以创建一个 MutableList 来添加每个新的卢旺达数字,并比较新生成的随机数不在您生成的列表中。如果是这样,你放弃是可以再次调用随机。

标签: android-studio sorting kotlin random


【解决方案1】:

有三种基本方法可以避免重复“随机”数字。如果它们不重复,那么它们当然不是真正随机的。

  • 小范围的数字,随机洗牌,洗牌后按顺序挑选。

  • 使用中等大小的号码,记录您选择的号码,并拒绝任何重复。如果您选择大部分可用数字,这会变慢。

  • 对于非常大的数字范围,您需要像加密这样的东西:将 0、1、2、3 ... 映射到(大)范围内的数字的一对一映射。例如,128 位加密将给出非重复 128 位数字的明显随机排序。

【讨论】:

    【解决方案2】:

    Sequences 是生成数据流并限制或过滤结果的好方法。

    import kotlin.random.Random
    import kotlin.random.nextInt
    
    val randomInts = generateSequence {
      // this lambda is the source of the sequence's values
      Random.nextInt(1..69)
    }
      // make the values distinct, so there's no repeated ints
      .distinct()
      // only fetch 6 values
      // Note: It's very important that the source lambda can provide
      //       this many distinct values! If not, the stream will
      //       hang, endlessly waiting for more unique values.
      .take(6)
      // sort the values
      .sorted()
      // and collect them into a Set
      .toSet()
    

    为确保此方法有效,这是一个使用 Kotest 的基于属性的测试。

    import io.kotest.core.spec.style.FunSpec
    import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasing
    import io.kotest.matchers.collections.shouldBeUnique
    import io.kotest.matchers.collections.shouldHaveSize
    import io.kotest.property.Arb
    import io.kotest.property.arbitrary.positiveInts
    import io.kotest.property.checkAll
    import kotlin.random.Random
    import kotlin.random.nextInt
    
    
    class RandomImageLogicTest : FunSpec({
    
      test("expect sequence of random ints is distinct, sorted, and the correct size") {
        checkAll(Arb.positiveInts(30)) { limit ->
    
          val randomInts = generateSequence { Random.nextInt(1..69) }
            .distinct()
            .take(limit)
            .sorted()
            .toSet()
    
          randomInts.shouldBeMonotonicallyIncreasing()
          randomInts.shouldBeUnique()
          randomInts.shouldHaveSize(limit)
        }
      }
    
    })
    

    测试通过!

    Test                                      Duration  Result
    expect sequence of random ints is di...   0.163s    passed
    

    【讨论】:

      【解决方案3】:
      val size = 6
      val s = HashSet<Int>(size)
      while (s.size < size) {
          s += Random.nextInt(1,69)
      }
      

      【讨论】:

        【解决方案4】:

        我创建一个简单的类,在构造函数中输入“from”数字(最小可能数字)和“to”(最大可能数字),类创建数字列表。 "nextInt()" 从集合中返回随机项并将其删除。

        class RandomUnrepeated(from: Int, to: Int) {
            private val numbers = (from..to).toMutableList()
            fun nextInt(): Int {
                val index = kotlin.random.Random.nextInt(numbers.size)
                val number = numbers[index]
                numbers.removeAt(index)
                return number
            }
        }
        

        用法:

        val r = RandomUnrepeated(0,100)
        r.nextInt()
        

        【讨论】:

          【解决方案5】:

          类似于@IR42 的回答,你可以这样做

          import kotlin.random.Random
          
          fun getUniqueRandoms() = sequence {
              val seen = mutableSetOf<Int>()
              while(true) {
                  val next = Random.nextInt()
                  // add returns true if it wasn't already in the set - i.e. it's not a duplicate
                  if (seen.add(next)) yield(next)
              }
          }
          
          fun main() {
              getUniqueRandoms().take(6).sorted().forEach(::println)
          }
          

          所以getUniqueRandoms 创建了一个独立的序列,并拥有它自己生成的数字的内部状态。对于调用者来说,它只是一个产生唯一值的基本序列,您可以随意使用它们。

          就像@rossum 说的那样,这实际上取决于您要生产多少 - 如果您生产很多,或者这个序列真的很长寿,那么随着时间的推移,这组看到的数字会变得非常大。此外,当您遇到越来越多的碰撞时,它会开始放慢速度,并且必须继续尝试找到尚未出现的碰撞。

          但在大多数情况下,这种事情还不错 - 如果您要生成数百万个数字,您可能想要对其进行基准测试,但对于像 6 这样的数字,甚至不值得担心!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-07-19
            • 2010-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-19
            • 1970-01-01
            相关资源
            最近更新 更多