Kotlin – Random numbers without repeating

Solution for Kotlin – Random numbers without repeating
is Given Below:

I have a question, how to prevent random numbers from being repeated.
By the way, can someone explain to me how to sort these random numbers?

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

There are three basic methods to avoid repeating ‘random’ numbers. If they don’t repeat then they are not really random of course.

  • with a small range of numbers, randomly shuffle the numbers and pick them in order after the shuffle.

  • with a medium size range of numbers, record the numbers you have picked, and reject any repeats. This will get slow if you pick a large percentage of the numbers available.

  • with a very large range of numbers you need something like an encryption: a one-to-one mapping which maps 0, 1, 2, 3 … to the numbers in the (large) range. For example a 128 bit encryption will give an apparently random ordering of non-repeating 128-bit numbers.

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

Sequences are a great way to generate streams of data and limit or filter the results.

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

To make sure this works, here’s a property-based-test using 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)
    }
  }

})

The test passes!

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

Similar to @IR42’s answer, you can do something like this

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

So getUniqueRandoms creates an independent sequence, and holds its own internal state of which numbers it’s produced. For the caller, it’s just a basic sequence that produces unique values, and you can consume those however you like.

Like @rossum says, this really depends on how many you’re going to produce – if you’re generating a lot, or this sequence is really long-lived, that set of seen numbers will get very large over time. Plus it will start to slow down as you get more and more collisions, and have to keep trying to find one that hasn’t been seen yet.

But for most situations, this kind of thing is just fine – you’d probably want to benchmark it if you’re producing, say, millions of numbers, but for something like 6 it’s not even worth worrying about!

I create simple class, in constructor you enter “from” number (minimal possible number) and “to” (maximal posible number), class create list of numbers.
“nextInt()” return random item from collection and remove it.

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

usage:

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