Last active
December 21, 2019 02:40
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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