Last active
October 12, 2018 09:41
-
-
Save Jellymath/7e187e62638011e947ff4b696ed37038 to your computer and use it in GitHub Desktop.
Some permutation fun code
This file contains 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
fun main() { | |
println(listOf(1, 2, 2).permutations()) | |
println(listOf(1, 2, 2).permutationsFromScala()) | |
println(listOf(1, 2, 2).permutationsFromScala(distinct = true)) | |
} | |
fun <T> Collection<T>.permutations(): List<List<T>> = when (size) { | |
0 -> emptyList() | |
1 -> listOf(listOf(first())) | |
else -> flatMapIndexed { i, x -> | |
(take(i) + drop(i + 1)).permutations().map { it + x } | |
} | |
} | |
fun <T> Iterable<T>.permutationsFromScala(distinct: Boolean = false): List<List<T>> = | |
if (none()) emptyList() | |
else PermutationIterator(this, distinct).asSequence().toList() | |
private class PermutationIterator<T>(initial: Iterable<T>, distinct: Boolean = false) : Iterator<List<T>> { | |
private val elements: MutableList<T> | |
private val indexes: Array<Int> | |
private var _hasNext = true | |
override fun hasNext(): Boolean = _hasNext | |
override fun next(): List<T> { | |
require(_hasNext) { "Next on empty iterator" } | |
val result = elements.toList() | |
var i = indexes.size - 2 | |
while (i >= 0 && indexes[i] >= indexes[i + 1]) i-- | |
if (i < 0) { | |
_hasNext = false | |
} else { | |
var j = indexes.size - 1 | |
while (indexes[j] <= indexes[i]) j-- | |
swap(i, j) | |
val len = (indexes.size - i) / 2 | |
var k = 1 | |
while (k <= len) { | |
swap(i + k, indexes.size - k) | |
k++ | |
} | |
} | |
return result | |
} | |
init { | |
val m = HashMap<T, Int>() | |
val (elems, idxs) = | |
if (distinct) (initial.map { it to m.getOrPut(it) { m.size } }.sortedBy { it.second }).unzip() | |
else initial.mapIndexed { index, t -> t to index }.unzip() | |
elements = elems.toMutableList() | |
indexes = idxs.toTypedArray() | |
} | |
private fun swap(i: Int, j: Int) { | |
indexes.swap(i, j) | |
elements.swap(i, j) | |
} | |
} | |
fun <T> Array<T>.swap(i: Int, j: Int) { | |
val temp = this[i] | |
this[i] = this[j] | |
this[j] = temp | |
} | |
fun <T> MutableList<T>.swap(i: Int, j: Int) { | |
val temp = this[i] | |
this[i] = this[j] | |
this[j] = temp | |
} | |
inline fun <T, R> Iterable<T>.flatMapIndexed(transform: (index: Int, T) -> Iterable<R>): List<R> { | |
return flatMapIndexedTo(ArrayList(), transform) | |
} | |
inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapIndexedTo( | |
destination: C, | |
transform: (index: Int, T) -> Iterable<R> | |
): C { | |
var index = 0 | |
for (item in this) | |
destination.addAll(transform(index++, item)) | |
return destination | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment