Skip to content

Instantly share code, notes, and snippets.

@wafer-li
Last active December 21, 2019 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wafer-li/8fa3fb28139927cdf8520f5ecf5013ae to your computer and use it in GitHub Desktop.
Save wafer-li/8fa3fb28139927cdf8520f5ecf5013ae to your computer and use it in GitHub Desktop.
A Random Sequencer generate sequence of random item within range which ensure no duplicate item in a range block
package profile.adapter
import profile.adapter.RandomSequencer.Companion.fromCharRange
import profile.adapter.RandomSequencer.Companion.fromIntRange
import profile.adapter.RandomSequencer.Companion.fromLongRange
import kotlin.random.Random
/**
* A Random Sequencer which accomplish :
* 1. Generate a sequence of random items within range.
* 2. The same initial seed will get the same sequence.
* 3. Within a range block, there is no duplicated items.
*
* For example, if you provide a range of 1 to 10 inclusively, then the first 10 items will not be duplicated,
* and the second 10 items and the third and so on.
*
* If you only need the random sequence of primitive types, you just need to use the handy method
* such as [fromIntRange], [fromCharRange] and [fromLongRange].
*
* However, if you want to generate random sequence of your custom types,
* you need to provide the [mapper] which turn the [ClosedRange] to a [Iterable]
*/
class RandomSequencer<T : Comparable<T>>(
private val initialSeed: Int,
private val range: ClosedRange<T>,
private val mapper: (range: ClosedRange<T>) -> Iterable<T>
) {
private var version = -1L
private val seedRandom = Random(initialSeed)
private var iterator = sequenceOf<T>().iterator()
fun toSequence(): Sequence<T> {
return generateSequence { next() }
}
fun next(): T {
if (!iterator.hasNext()) {
iterator = generateRandomSequence()
}
return iterator.next()
}
fun reset() {
version = -1L
iterator = sequenceOf<T>().iterator()
}
private fun generateRandomSequence(): Iterator<T> {
val random = Random(obtainSeed())
val iterable = mapper(range)
return iterable.shuffled(random).iterator()
}
private fun obtainSeed(): Long {
val result = if (version < 0) {
initialSeed.toLong()
} else {
(initialSeed + seedRandom.nextInt()).toLong()
}
version++
return result
}
companion object {
fun fromIntRange(initialSeed: Int, intRange: IntRange): RandomSequencer<Int> =
RandomSequencer(initialSeed, intRange) { intRange.asIterable() }
fun fromCharRange(initialSeed: Int, charRange: CharRange): RandomSequencer<Char> =
RandomSequencer(initialSeed, charRange) { charRange.asIterable() }
fun fromLongRange(initialSeed: Int, longRange: LongRange): RandomSequencer<Long> =
RandomSequencer(initialSeed, longRange) { longRange.asIterable() }
}
}
fun main() {
val range = 1..10
val intRandomSequence = RandomSequencer.fromIntRange(1000704, range)
val iterator = intRandomSequence.toSequence().iterator()
for (i in 1..100) {
println("$i : ${iterator.next()}")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment