Skip to content

Instantly share code, notes, and snippets.

@loehnertz
Created December 6, 2021 20:55
Show Gist options
  • Save loehnertz/3b118d66fc349f47993f8e6b9ffccf7a to your computer and use it in GitHub Desktop.
Save loehnertz/3b118d66fc349f47993f8e6b9ffccf7a to your computer and use it in GitHub Desktop.
Handy Kotlin Extension Functions
/**
* Swaps the order of the elements of the given [Pair] in a type-safe manner.
*
* Example:
* ```
* Pair("David", 32).swap() // Pair(32, "David")
* ```
*/
fun <A, B> Pair<A, B>.swap(): Pair<B, A> = this.second to this.first
infix fun <A, B, C> Pair<A, B>.to(third: C): Triple<A, B, C> = Triple(first, second, third)
fun Boolean.whenTrue(block: (Boolean) -> Unit): Boolean {
if (this) block(this)
return this
}
fun Boolean.whenFalse(block: (Boolean) -> Unit): Boolean {
if (!this) block(this)
return this
}
fun <T : Any> Optional<T>.toNullable(): T? = this.orElse(null)
/**
* Returns the [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product)
* of the two given collections. The function works generically on any two types.
*
* @return A list of [Pair] with the value's order corresponding to the order that
* the arguments were passed into the function.
*/
fun <T, U> Collection<T>.cartesianProduct(collection2: Collection<U>): List<Pair<T, U>> {
return this.flatMap { lhs: T -> collection2.map { rhs: U -> lhs to rhs } }
}
/**
* Returns the first [`n`][percentage] percent of items out of the given [Collection].
* The percentage gets rounded down to the next integer regarding the size of the returned [List].
*/
fun <T> Collection<T>.takePercent(percentage: Double): List<T> {
require(percentage in 0.0..1.0) { "A floating point percentage is required" }
return this.take((this.size * percentage).roundToInt())
}
/**
* Merges the given [collection][Collection] of type-equivalent [maps][Map] together,
* while grouping the values of each key together and finally applying the given
* [lambda][valueMergeFunction] to each value to merge the list of values of each key
* into a single value such that the returned map has the same type-signature again.
*/
fun <K, V> Collection<Map<K, V>>.merge(valueMergeFunction: (List<V>) -> V): Map<K, V> {
return this
.flatMap { it.entries }
.groupBy({ it.key }) { it.value }
.mapValues { valueMergeFunction(it.value) }
}
/**
* Returns if the given range contains the [other] range.
*/
operator fun <T : Comparable<T>> ClosedRange<T>.contains(other: ClosedRange<T>): Boolean {
return this.start in other && this.endInclusive in other
}
/**
* Returns if the given range overlaps with the [other] range.
*/
fun <T : Comparable<T>> ClosedRange<T>.overlaps(other: ClosedRange<T>): Boolean {
return this.start in other || this.endInclusive in other
}
/**
* Returns any given [Map] with its keys and values reversed to a [MultiValueMap]
* such that duplicate values will group together their keys.
* Note that the returned type is immutable.
*/
fun <K, V> Map<K, V>.reverseToMultiMap(): MultiValueMap<V, K> {
return HashMap<V, MutableList<K>>(this.count()).also { reversedMap: HashMap<V, MutableList<K>> ->
this.entries.forEach { entry: Map.Entry<K, V> ->
reversedMap[entry.value] =
reversedMap.getOrPut(entry.value) { mutableListOf() }.also { it.add(entry.key) }
}
}.toMultiMap()
}
/**
* Converts any given [Map] to a [MultiValueMap].
* Note that the returned type is immutable.
*/
fun <K, V> Map<K, List<V>>.toMultiMap(): MultiValueMap<K, V> {
return unmodifiableMultiValueMap(toMultiValueMap(this))
}
/**
* Returns how many percent of the items of the given [Collection] satisfy the given [predicate].
*
* @return A percentage represented as a floating-point number between 0 and 1.
*/
fun <T> Collection<T>.percentage(predicate: (T) -> Boolean): Double {
return this.count { predicate(it) } / this.count().toDouble()
}
@realityexpander
Copy link

thanks for posting this, very helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment