Kotlin-不重复的随机数

k5ifujac  于 2022-11-25  发布在  Kotlin
关注(0)|答案(6)|浏览(550)

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

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

beq87vna1#

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

  • 对于小范围的号码,随机地洗牌号码,并在洗牌后按顺序挑选它们。
  • 选择一个中等大小的号码范围,记录下你已经挑选的号码,并拒绝任何重复的号码。2如果你挑选了一个很大比例的号码,这个过程会变慢。
  • 对于非常大范围的数字,您需要类似加密的东西:一对一Map,将0、1、2、3 ...Map到(大)范围内的数字。例如,128位加密将给予不重复的128位数字的明显随机排序。
8dtrkrch

8dtrkrch2#

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

run in Kotlin Playground
为了确保这一点,下面使用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
fdx2calv

fdx2calv3#

val size = 6
val s = HashSet<Int>(size)
while (s.size < size) {
    s += Random.nextInt(1,69)
}
cwdobuhd

cwdobuhd4#

我创建了一个简单类,在构造函数中输入“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()
8fq7wneg

8fq7wneg5#

与@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这样的数字,甚至不值得担心!

6fe3ivhb

6fe3ivhb6#

您可以使用Set和MutableSet来代替List:

val mySet = mutableSetOf<Int>() 
while (mySet.size < 6) 
   mySet.add(Random.nextInt(1, 69))

相关问题