In Kotlin, can I have two random values with the second one omitting the first random number?

Viewed 182

Here is what I am trying to say:

val firstNumbers = (1..69).random()
val secondNumbers = (1..69).random()

I would like the secondNumbers to omit the random number picked in firstNumbers

3 Answers

If you're just generating two numbers, what you could do is lower the upper bound for secondNumbers down to 68, then add 1 if it's greater than or equal to the first number. This will ensure an even distribution:

val firstNumber = (1..69).random()
var secondNumber = (1..68).random()
if (secondNumber >= firstNumber) {
    secondNumber += 1
}

For generating more than 2 numbers, the following code should work:

fun randoms(bound: Int, n: Int): List<Int> {
    val mappings = mutableMapOf<Int, Int>()
    val ret = mutableListOf<Int>()
    for (i in 0 until n) {
        val num = (1..(bound - i)).random()
        ret.add(mappings.getOrDefault(num, num))
        mappings.put(num, mappings.getOrDefault(bound - i, bound - i))
    }
    return ret
}

It tries to emulate Fisher-Yates shuffling while only keeping track of swaps that happened, thus greatly reducing memory usage when n is much less than bound. If n is very close to bound, then the answer by @lukas.j is much cleaner to use and probably also faster.

It can be used like so:

randoms(69, 6) // might return [17, 36, 60, 48, 69, 21]

(I'd encourage people to double-check the uniformity and correctness of the algorithm, but it seems good to me)

random() is the wrong approach, rather use shuffled() and then take the first two elements from the list with take(). And it is a oneliner:

val (firstNumber, secondNumber) = (1..69).shuffled().take(2)

println(firstNumber)
println(secondNumber)

Another approach could be to find one number in range 1..69, remove that number from the range and find the second one.

val first = (1..69).random()
val second = ((1..69) - first).random()

Edit: As per your comment, you want 6 different numbers within this range. You can do that like this.

val values = (1..69).toMutableList()
val newList = List(6) {
    values.random().also { values.remove(it) }
}
Related