Skip to content

Instantly share code, notes, and snippets.

@Jellymath
Last active October 12, 2018 09:41
Show Gist options
  • Save Jellymath/7e187e62638011e947ff4b696ed37038 to your computer and use it in GitHub Desktop.
Save Jellymath/7e187e62638011e947ff4b696ed37038 to your computer and use it in GitHub Desktop.
Some permutation fun code
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