Curated collection of useful Kotlin 1.3 snippets that you can understand quickly, using only stdlib functionality.
Snippets are optimized for readability and comprehension, sometimes at the expense of performance.
Note: This project is inspired by, but in no way affiliated with, 30 Seconds of Code.
Functions operating on the most fundamental data structure: List.
View contents
all
allEqual
any
bifurcate
bifurcateBy
chunk
compact
countBy
countOccurrences
concat
corresponds
crossProduct
cycle
difference
differenceBy
differenceWith
distinct
drop
dropRight
dropRightWhile
dropWhile
endsWith
everyNth
existsUnique
filterNonUnique
filterNonUniqueBy
findLast
findLastIndex
forEachRight
groupBy
hasDuplicates
hasSubList
head
indexOfAll
initial
initialize2DList
initializeListWithRange
initializeListWithValue
intersection
intersectionBy
intersectionWith
intersperse
join
last
longest
mapObject
maxN
minN
none
nthElement
partition
partitioningBy
permutations
product
pull
pullAtIndex
pullAtValue
reduceSuccessive
reject
remove
rotateLeft
rotateRight
sample
sampleSize
segmentLength
shank
shuffle
slideBy
sortOrder
span
splitAt
startsWith
symmetricDifference
symmetricDifferenceBy
symmetricDifferenceWith
tail
take
takeRight
takeRightWhile
takeWhile
union
unionBy
unionWith
unzip
without
zip
zipAll
zipKeysValues
zipWith
zipWithIndex
zipWithNext
Kotlin's first class functions make it easy to manipulate functions.
View contents
Functions operating on Kotlin's built in Lazy type.
View contents
Functions operating on Maps.
- 30 Seconds of Code (JavaScript)
- 30 Seconds of Knowledge
- 30 Seconds of Java
- 30 Seconds of React
- 30 Seconds of Python
- 30 Seconds of PHP
Returns true
if the provided predicate function returns true
for all elements in a list, false
otherwise.
fun <T> all(list: List<T>, predicate: (T) -> Boolean): Boolean =
list.all(predicate)
Checks if all elements in a list are equal.
fun <T> allEqual(list: List<T>): Boolean =
if (list.isEmpty()) false else list.all { it == list[0] }
Returns true
if the provided predicate function returns true
for at least one element in a list, false
otherwise.
fun <T> any(list: List<T>, predicate: (T) -> Boolean): Boolean =
list.any(predicate)
Splits list into two groups. For every element in a list, if the corresponding boolean in another list is true, add the element to the first group; otherwise, add it to the second group.
// For example:
bifurcate(listOf("beep", "boop", "foo", "bar"), listOf(true, true, false, true)) // [[beep, boop, bar], [foo]]
fun <T> bifurcate(list: List<T>, filter: List<Boolean>): Pair<List<T>, List<T>> {
require(list.size == filter.size)
return list.zip(filter).partition { it.second }
.let { (list1, list2) -> list1.map { it.first } to list2.map { it.first } }
}
Splits values into two groups according to a predicate function, which specifies which group an element in the input list belongs to. If the predicate function returns true, the list element belongs to the first group; otherwise, it belongs to the second group.
fun <T> bifurcateBy(list: List<T>, predicate: (T) -> Boolean): Pair<List<T>, List<T>> =
list.partition(predicate)
Chunks a list into smaller lists of a specified size. The last list in the resulting list may have less elements than the given size.
// For example:
chunk(listOf(1, 2, 3, 4, 5), 2) // [[1 ,2], [3, 4], [5]]
fun <T> chunk(list: List<T>, size: Int): List<List<T>> =
list.chunked(size)
Removes "falsey" values from a list.
Kotlin doesn't distinguish falsey values but they are (false
, null
, 0
, ""
, []
, and NaN
).
fun <T> compact(list: List<T?>): List<T> {
fun isTruthy(t: T?): Boolean = when(t) {
null -> false
is Boolean -> t
is Double -> t != Double.NaN
is Number -> t.toInt() != 0
is String -> !t.isEmpty()
is Array<*> -> t.size != 0
is Collection<*> -> !t.isEmpty()
else -> true
}
@Suppress("UNCHECKED_CAST")
return list.filter(::isTruthy) as List<T>
}
Groups the elements of a list based on the given function and returns the count of elements in each group.
// For example:
countBy(listOf(6.1, 4.2, 6.3)) { floor(it) } // {4.0: 1, 6.0: 2}
countBy(listOf("one", "two", "three")) { it.length } // {3: 2, 5: 1}
fun <T, K> countBy(list: List<T>, function: (T) -> K): Map<K, Int> =
list.groupingBy(function).eachCount()
Counts the occurrences of a value in a list, using a provided equality function.
fun <T> countOccurrences(list: List<T>, target: T, equals: (T, T) -> Boolean = Objects::equals): Int =
list.count { equals(target, it) }
Concatenates multiple lists into a single list, preserving the order of the passed in elements.
fun <T> concat(first: List<T>, vararg others: List<T>): List<T> =
first.asSequence().plus(others.asSequence().flatten()).toList()
Tests whether every element of the first list relates to the corresponding element in the second list by satisfying the given predicate.
// For example:
corresponds(listOf(1, 2, 3), listOf(2, 3, 4)) { i1, i2 -> i1 == i2 - 1 } // true
fun <T, U> corresponds(first: List<T>, second: List<U>, predicate: (T, U) -> Boolean): Boolean =
(first.size == second.size) && (first.zip(second).all { (t, u) -> predicate(t, u) })
Creates a cross product: forming a pair from each value in the first list to each value in the second list.
// For example:
crossProduct(listOf(1, 2), listOf('a', 'b')) // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
fun <T, U> crossProduct(first: List<T>, second: List<U>): List<Pair<T, U>> =
first.flatMap { a -> second.map { b -> a to b } }
Produces a Sequence
which cycles indefinitely through the given list.
// For example:
cycle(listOf(1, 2, 3)) // 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3...
fun <T> cycle(list: List<T>): Sequence<T> =
generateSequence(if (list.isNotEmpty()) 0 else null) { (it + 1) % list.size }
.map { list[it] }
Returns a list of elements contained in the first list that are not present in the second list.
// For example:
difference(listOf(1, 2, 3), listOf(1, 2, 4)) // [3]
fun <T> difference(first: List<T>, second: List<T>): List<T> =
(first subtract second).toList()
Returns a list of elements contained in the first list that are not present in the second list, after applying the provided function to each list element of both.
fun <T, R> differenceBy(first: List<T>, second: List<T>, function: (T) -> R): List<T> =
with(second.toSet().map(function)) {
first.filterNot { contains(function(it)) }
}
Filters out all elements from the first list for which the comparator function does not return true
for that element and every element in the second list.
fun <T> differenceWith(first: List<T>, second: List<T>, function: (T, T) -> Boolean): List<T> =
first.filter { a -> second.none { b -> function(a, b) } }
Returns all distinct elements.
fun <T> distinct(list: List<T>): List<T> =
list.distinct()
Returns a new list with n
elements removed from the left.
fun <T> drop(list: List<T>, n: Int): List<T> =
list.drop(n)
Returns a new list with n
elements removed from the right.
fun <T> dropRight(list: List<T>, n: Int): List<T> =
list.dropLast(n)
Removes elements from the end of a list until the passed function returns true
. Returns the remaining elements in the list.
fun <T> dropRightWhile(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.dropLastWhile(predicate)
Removes elements from the beginning of a list until the passed function returns true
. Returns the remaining elements in the list.
fun <T> dropWhile(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.dropWhile(predicate)
Checks whether the given list ends with the given sublist.
fun <T> endsWith(list: List<T>, subList: List<T>): Boolean =
list.takeLast(subList.size) == subList
Returns every nth element in a list.
// For example:
everyNth(listOf(1, 2, 3, 4, 5, 6), 2) // [ 2, 4, 6 ]
fun <T> everyNth(list: List<T>, nth: Int): List<T> =
list.windowed(nth, nth, partialWindows = false).map { it.last() }
Checks if a unique element exists such that the predicate holds.
// For example:
existsUnique(listOf(1, 2, 3, 4, 5, 3)) { it == 3 } // false
fun <T> existsUnique(list: List<T>, predicate: (T) -> Boolean): Boolean {
var exists = false
for (t in list) {
if (predicate(t)) {
if (exists) {
return false
} else {
exists = true
}
}
}
return exists
}
Filters out the non-unique values in a list.
fun <T> filterNonUnique(list: List<T>): List<T> =
list.distinct()
Filters out the non-unique values in an list, after applying the given function.
// For example:
filterNonUniqueBy(listOf('a', 'b', 'c')) { 1 } // [a]
fun <T, K> filterNonUniqueBy(list: List<T>, function: (T) -> K): List<T> =
list.distinctBy(function)
Returns the last element for which the provided function returns true, or null if none is found.
fun <T> findLast(list: List<T>, predicate: (T) -> Boolean): T? =
list.findLast(predicate)
Returns the index of the last element for which the provided function returns true, or -1 if none is found.
fun <T> findLastIndex(list: List<T>, predicate: (T) -> Boolean): Int =
list.indexOfLast(predicate)
Executes a provided function once for each list element, starting from the list's last element.
fun <T> forEachRight(list: List<T>, action: (T) -> Unit): Unit =
list.reversed().forEach(action)
Groups the elements of a list based on the given function.
// For example:
groupBy(listOf(6.1, 4.2, 6.3)) { floor(it) } // {4.0: [4.2], 6.0: [6.1, 6.3]}
groupBy(listOf("one", "two", "three")) { it.length } // {3: [one, two], 5: [three]}
fun <T, K> groupBy(list: List<T>, function: (T) -> K): Map<K, List<T>> =
list.groupBy(function)
Returns true if duplicate values exist in the list, false otherwise.
fun <T> hasDuplicates(list: List<T>): Boolean =
list.toSet().size != list.size
Checks whether the given list contains the given sublist.
tailrec fun <T> hasSubList(list: List<T>, subList: List<T>): Boolean =
when {
subList.isEmpty() -> true
list.isEmpty() -> subList.isEmpty()
list.take(subList.size) == subList -> true
else -> hasSubList(list.drop(1), subList)
}
Returns the head of a list.
fun <T> head(list: List<T>): T =
list.first()
Returns all indices in a list where a given value is present. If the value never occurs, returns an empty list.
// For example:
indexOfAll(listOf(1, 2, 3, 1, 2, 3), 1) // [0, 3]
indexOfAll(listOf(1, 2, 3), 4) // []
fun <T> indexOfAll(list: List<T>, target: T): List<Int> =
list.withIndex().filter { it.value == target }.map { it.index }
Returns all the elements of an array except the last one.
fun <T> initial(list: List<T>): List<T> =
list.dropLast(1)
Initializes a 2D list of given width and height and value.
// For exmaple:
initialize2DList(2, 2, 0) // [[0, 0], [0, 0]]
fun <T> initialize2DList(width: Int, height: Int, value: T): List<List<T>> =
List(height) { List(width) { value } }
Initializes a list containing the numbers in the specified range, where start
and stop
are inclusive with their common difference step
.
// For example:
initializeListWithRange(0, 9, 2) // [0, 2, 4, 6, 8]
fun initializeListWithRange(start: Int, stop: Int, step: Int): List<Int> =
(start..stop step step).toList()
Initializes and fills a list with the specified value.
// For example:
initializeListWithValue(5, 2) // [2, 2, 2, 2, 2]
fun <T> initializeListWithValue(size: Int, value: T): List<T> =
List(size) { value }
Returns a list of elements that exist in both lists.
// For example:
intersection(listOf(1, 2, 3), listOf(4, 3, 2)) // [2, 3]
fun <T> intersection(first: List<T>, second: List<T>): List<T> =
(first intersect second).toList()
Returns a list of elements that exist in both lists, after applying the provided function to each element of both.
// For example:
intersectionBy(listOf(2.1, 1.2), listOf(2.3, 3.4)) { floor(it) } // [2.1]
fun <T, R> intersectionBy(first: List<T>, second: List<T>, function: (T) -> R): List<T> =
with(second.toSet().map(function)) {
first.filter { contains(function(it)) }
}
Returns a list of elements that exist in both lists, using a provided comparator function.
// For example:
intersectionWith(listOf(1.0, 1.2, 1.5, 3.0, 0.0), listOf(1.9, 3.0, 0.0, 3.9)) { a, b -> round(a) == round(b) } // [1.5, 3.0, 0.0]
fun <T> intersectionWith(first: List<T>, second: List<T>, function: (T, T) -> Boolean): List<T> =
first.filter { a -> second.any { b -> function(a, b) } }
Inserts an element between all elements of the given list.
// For example:
intersperse(listOf('a', 'b', 'c', 'd'), '0') // [a, 0, b, 0, c, 0, d]
fun <T> intersperse(list: List<T>, element: T): List<T> =
List(list.size) { index -> listOf(list[index], element) }.flatten().dropLast(1)
Joins all elements of a list into a string.
fun <T> join(list: List<T>, separator: String = ", "): String =
list.joinToString(separator)
Returns the last element of a list.
fun <T> last(list: List<T>): T =
list.last()
Returns the longest collection in the list, or null if the list has no collections. If multiple collections have the same size, the first one will be returned.
fun <T> longest(list: List<Collection<T>>): Collection<T>? =
list.maxBy { it.size }
Maps the elements of a list to the result of applying a function to that element.
// For example:
mapObject(listOf(1, 2, 3)) { it * it } // { 1: 1, 2: 4, 3: 9 }
fun <T, R> mapObject(list: List<T>, function: (T) -> R): Map<T, R> =
list.associateWith(function)
Returns the n
maximum elements from the provided list.
If n
is greater than or equal to the provided list's length, then return the original list (sorted in descending order).
fun <T : Comparable<T>> maxN(list: List<T>, n: Int): List<T> =
list.sortedDescending().take(n)
Returns the n
minimum elements from the provided list.
If n
is greater than or equal to the provided list's length, then return the original list (sorted in ascending order).
fun <T : Comparable<T>> minN(list: List<T>, n: Int): List<T> =
list.sorted().take(n)
Returns true
if the provided predicate function returns false
for all elements in a list, false
otherwise.
// For example:
none(listOf(0, 1, 3, 0)) { it == 2} // true
none(listOf(-1, 1, 2)) { it <= 0 } // false
fun <T> none(list: List<T>, predicate: (T) -> Boolean): Boolean =
list.none(predicate)
Returns the nth element of a list.
If the index is out of bounds, throws IndexOutOfBoundsException
.
fun <T> nthElement(list: List<T>, n: Int): T =
list[n]
Groups the elements into two lists, the first containing all elements for which the predicate evaluated to true, and the second containing all other elements.
fun <T> partition(list: List<T>, predicate: (T) -> Boolean): Pair<List<T>, List<T>> =
list.partition(predicate)
Partitions the input elements according to a predicate and organizes them into a Map<Boolean, List<T>
.
Inspired by the JDK's Collectors::partitioningBy
.
fun <T> partitioningBy(list: List<T>, predicate: (T) -> Boolean): Map<Boolean, List<T>> =
list.groupBy(predicate)
Computes all the permutations of the given list. List elements are treated unique based on their index, so a list with equal elements will return duplicate lists.
Note: this implementation uses non stack safe recursion
kotlin // For example: permutations(listOf(1, 2, 3)) // [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
fun <T> permutations(list: List<T>): List<List<T>> {
fun <T> List<T>.removeAtIndex(index: Int): List<T> = take(index) + drop(index + 1)
fun <T> List<T>.prepend(element: T): List<T> = listOf(element) + this
return when {
list.isEmpty() -> emptyList()
list.size == 1 -> listOf(list)
else -> list.foldIndexed(mutableListOf()) { index, acc, t ->
acc.apply {
addAll(permutations(list.removeAtIndex(index)).map { it.prepend(t) })
}
}
}
}
Creates a cross product: applying the provided function to each value in the first list along with each value in the second list
fun <T, U, R> product(first: List<T>, second: List<U>, function: (T, U) -> R): List<R> =
first.flatMap { t -> second.map { u -> function(t, u) } }
Filters out the elements specified.
// For example:
pull(listOf('a', 'b', 'c', 'a', 'b', 'c'), 'a', 'c') // [b, b]
fun <T> pull(list: List<T>, vararg elements: T): List<T> =
with(elements.toSet()) {
list.filterNot { contains(it) }
}
Filters out the indices specified.
// For example:
pullAtIndex(listOf('a', 'b', 'c', 'd'), 1, 2) // [a, d]
fun <T> pullAtIndex(list: List<T>, vararg indices: Int): List<T> =
with(indices.toSet()) {
list.filterIndexed { index, _ -> !contains(index) }
}
Filters out the elements specified and returns them.
// For example:
pullAtValue(listOf('a', 'b', 'c', 'd'), 'b', 'd', 'e') // [b, d]
fun <T> pullAtValue(list: List<T>, vararg elements: T): List<T> =
with(elements.toSet()) {
list.filter { contains(it) }
}
This function is also commonly known as scan
.
Applies a function against an accumulator and each element in the list (from left to right), returning a new list of successively calculated values.
// For example:
reduceSuccessive(listOf(1, 2, 3, 4, 5, 6), 0) { acc, int -> acc + int } // [1, 3, 6, 10, 15, 21]
fun <T, R> reduceSuccessive(list: List<T>, identity: R, function: (R, T) -> R): List<R> {
fun <T> List<T>.lastOrElse(t: T): T = lastOrNull() ?: t
return list.fold(emptyList()) { acc, t -> acc + function(acc.lastOrElse(identity), t) }
}
Return a new list which removes elements from the list for which the given predicate returns true
.
// For example:
reject(listOf(1, 2, 3, 4, 5)) { it % 2 == 0 } // [1, 3, 5]
reject(listOf("Apple", "Pear", "Kiwi", "Banana")) { it.length > 4 } // [Pear, Kiwi]
fun <T> reject(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.filterNot(predicate)
Returns a new list which removes elements from the list for which the given predicate returns false
.
// For example:
remove(listOf(1, 2, 3, 4)) { it % 2 == 0 } // [2, 4]
fun <T> remove(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.filter(predicate)
Returns a new list which circular rotates the elements by the specified distance to the left direction. This implementation throws an exception when n is negative, though in reality a negative rotation to the left can be considered a positive rotation to the right.
// For example:
rotateLeft(listOf(1, 2, 3, 4, 5), 2) // [3, 4, 5, 1, 2]
fun <T> rotateLeft(list: List<T>, n: Int): List<T> =
list.slice(n until list.size) + list.slice(0 until n)
Returns a new list which circular rotates the elements by the specified distance to the right direction. This implementation throws an exception when n is negative, though in reality a negative rotation to the right can be considered a positive rotation to the left.
// For example:
rotateRight(listOf(1, 2, 3, 4, 5), 2) // [4, 5, 1, 2, 3]
fun <T> rotateRight(list: List<T>, n: Int): List<T> =
list.takeLast(n % list.size) + list.dropLast(n % list.size)
Returns a random element from a list.
fun <T> sample(list: List<T>): T =
list.random()
Gets n
random elements from a list, up to the size of the list.
fun <T> sampleSize(list: List<T>, n: Int): List<T> =
list.shuffled().take(n)
Computes length of longest segment within the given list whose elements all satisfy some predicate.
// For example:
segmentLength(listOf('d', 'e', 'f', 'a', 'b', 'c', 'd')) { char -> char == 'a' || char == 'b' || char == 'c' } // 3
fun <T> segmentLength(list: List<T>, predicate: (T) -> Boolean): Int =
list.fold(0 to 0) { (longest, current), t -> if (predicate(t)) longest to current + 1 else max(longest, current) to 0 }.first
Returns a new list with changes in the contents of this list, removing or replacing existing elements and/or adding new elements.
// For example:
val names = listOf("alpha", "bravo", "charlie")
shank(names, 1, 0, "delta") // [alpha, delta, bravo, charlie]
shank(names, 1, 1) // [alpha, charlie]
start
- Index at which to start changing the list
deleteCount
- the number of list elements to remove, beginning from start
elements
- the elements to add to the list, beginning from start
fun <T> shank(list: List<T>, start: Int = 0, deleteCount: Int = 0, vararg elements: T): List<T> =
list.slice(0 until start) + elements + list.drop(start + deleteCount)
Returns a new list with the elements of this list randomly shuffled.
fun <T> shuffle(list: List<T>): List<T> =
list.shuffled()
Slides a non-overlapping window of a variable size over the given list.
Each window contains elements that are equal according to the given classifier function.
// For example:
slideBy(listOf(1, 2, 3, 3, 3, 4, 5)) { it } // [[1], [2], [3, 3, 3], [4], [5]]
slideBy(listOf(1, 2, 3, 10, 12, 5, 7, 20, 29)) { it / 10 } // [[1, 2, 3], [10, 12], [5, 7], [20, 29]]
fun <T, R> slideBy(list: List<T>, classifier: (T) -> R): List<List<T>> {
tailrec fun slideBy_(list: List<T>, acc: MutableList<List<T>>): MutableList<List<T>> =
if (list.isEmpty())
acc
else
slideBy_(list.dropWhile { classifier(it) == classifier(list.first()) }, acc.apply { add(list.takeWhile { classifier(it) == classifier(list.first()) } )} )
return slideBy_(list, mutableListOf())
}
Returns 1
if the list is sorted in ascending order, -1
if it is sorted in descending order or 0
if it is not sorted.
A list with all equal values is considered sorted ascending.
// For example:
isSorted(listOf(0, 1, 2, 2)) // 1
isSorted(listOf(4, 3, 2)) // -1
isSorted(listOf(4, 3, 5)) // 0
fun <T : Comparable<T>> sortOrder(list: List<T>): Int =
with(list.sorted()) {
when {
this == list -> 1
this.asReversed() == list -> -1
else -> 0
}
}
Returns a pair where the first element is the longest prefix of elements that satisfies the given predicate, and the second element is the remainder.
fun <T> span(list: List<T>, predicate: (T) -> Boolean): Pair<List<T>, List<T>> =
list.takeWhile(predicate) to list.dropWhile(predicate)
Splits the given list at the first element which satisfies the predicate.
// For example:
splitAt(listOf(1, 2, 3, 4, 5)) { it == 3 } // [[1, 2], [3, 4, 5]]
fun <T> splitAt(list: List<T>, predicate: (T) -> Boolean): Pair<List<T>, List<T>> =
list.takeWhile { !predicate(it) } to list.dropWhile { !predicate(it) }
Checks whether the given list starts with the given sublist.
fun <T> startsWith(list: List<T>, subList: List<T>): Boolean =
list.take(subList.size) == subList
Returns the symmetric difference between two lists, without filtering out duplicate values.
// For example:
symmetricDifference(listOf(1, 2, 3), listOf(1, 2, 4)) // [3, 4]
symmetricDifference(listOf(1, 2, 2), listOf(1, 3, 1)) // [2, 2, 3]
fun <T> symmetricDifference(first: List<T>, second: List<T>): List<T> =
((first subtract second) + (second subtract first)).toList()
Returns the symmetric difference between two lists, after applying the provided function to each element of both.
// For example:
symmetricDifferenceBy(listOf(2.1, 1.2), listOf(2.3, 3.4)) { floor(it) } // [1.2, 3.4]
fun <T, R> symmetricDifferenceBy(first: List<T>, second: List<T>, function: (T) -> R): List<T> {
val mapFirst = first.toSet().map(function)
val mapSecond = second.toSet().map(function)
return first.filterNot { mapSecond.contains(function(it)) } + second.filterNot { mapFirst.contains(function(it)) }
}
Returns the symmetric difference between two lists, using a provided function as a comparator.
// For example:
symmetricDifferenceWith(
listOf(1.0, 1.2, 1.5, 3.0, 0.0),
listOf(1.9, 3.0, 0.0, 3.9),
{ a, b -> round(a) == round(b) }
) // [1.0, 1.2, 3.9]
fun <T> symmetricDifferenceWith(first: List<T>, second: List<T>, function: (T, T) -> Boolean): List<T> =
first.filter { a -> second.none { b -> function(a ,b) } } +
second.filter { b -> first.none { a -> function(a, b) } }
Returns all elements in a list except for the first one.
fun <T> tail(list: List<T>): List<T> =
list.drop(1)
Returns the first n
elements.
Use Array.prototype.slice()
to create a slice of the array with n
elements taken from the beginning.
fun <T> take(list: List<T>, n: Int): List<T> =
list.take(n)
Returns the last n
elements.
fun <T> takeRight(list: List<T>, n: Int): List<T> =
list.takeLast(n)
Returns the last n
elements satisfying the given predicate.
// For example:
takeRightWhile(listOf(1, 2, 3, 4)) { it >= 3 } // [3, 4]
fun <T> takeRightWhile(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.takeLastWhile(predicate)
Returns the first n
elements satisfying the given predicate.
// For example:
takeWhile(listOf(1, 2, 3, 4)) { it < 3 } // [1, 2]
fun <T> takeWhile(list: List<T>, predicate: (T) -> Boolean): List<T> =
list.takeWhile(predicate)
Returns every element that exists in any of the two lists, removing duplicates.
// For example:
union(listOf(1, 2, 3), listOf(4, 3, 2)) // [1, 2, 3, 4]
fun <T> union(first: List<T>, second: List<T>): List<T> =
(first union second).toList()
Returns every element that exists in any of the two lists once, after applying the provided function to each element of both.
// For example:
unionBy(listOf(2.1), listOf(1.2, 2.3)) { floor(it) } // [2.1, 1.2]
fun <T, R> unionBy(first: List<T>, second: List<T>, function: (T) -> R): List<T> {
val mapFirst = first.toSet().map(function)
return (first.toSet() + second.toSet().filterNot { mapFirst.contains(function(it)) }).toList()
}
Returns every element that exists in any of the two lists once, using a provided comparator function.
// For example:
unionWith(listOf(1.0, 1.2, 1.5, 3.0, 0.0), listOf(1.9, 3.0, 0.0, 3.9)) { a, b -> round(a) == round(b) } // [1.5, 3.0, 0.0, 3.9]
fun <T> unionWith(first: List<T>, second: List<T>, function: (T, T) -> Boolean): List<T> =
(first.filter { a -> second.any { b -> function(a, b) } } union
second.filter { b -> first.any { a -> function(a, b) } }).toList()
Transforms a list of pairs to a pair of lists.
fun <T, U> unzip(list: List<Pair<T, U>>): Pair<List<T>, List<U>> =
list.unzip()
Returns a list of pairs built from the elements of each list with the same index. The returned list has length of the shortest list, so the longer list has some ignored elements.
fun <T, U> zip(first: List<T>, second: List<U>): List<Pair<T, U>> =
first.zip(second)
Returns a list of pairs built from the elements of each list with the same index, using the default value if any list is shorter. The returned list has length of the longest list
// For example:
zipAll(listOf(1, 2, 3), 0, listOf('a', 'b', 'c', 'd', 'e'), 'z') // [[1, a], [2, b], [3, c], [0, d], [0, e]]
fun <T, U> zipAll(first: List<T>, defaultT: T, second: List<U>, defaultU: U): List<Pair<T, U>> {
val firstIt = first.iterator()
val secondIt = second.iterator()
return object : Iterator<Pair<T, U>> {
override fun hasNext(): Boolean =
firstIt.hasNext() || secondIt.hasNext()
override fun next(): Pair<T, U> {
val t = if (firstIt.hasNext()) firstIt.next() else defaultT
val u = if (secondIt.hasNext()) secondIt.next() else defaultU
return t to u
}
}.asSequence().toList()
}
Zip a list of keys and a list of values into a Map. Since a Map cannot have duplicate keys, if the list of keys has any duplicates, only the last one will be kept.
fun <K, V> zipKeysValues(keys: List<K>, values: List<V>): Map<K, V> =
keys.zip(values).toMap()
Returns a list formed by applying the given function to elements of matching indices in both lists. The returned list has length of the shortest list, so the longer list has some ignored elements.
fun <T, U, R> zipWith(first: List<T>, second: List<U>, function: (T, U) -> R): List<R> =
first.zip(second).map { (t, u) -> function(t, u) }
Returns a list of pairs built from the elements of the list along with its index.
fun <T> zipWithIndex(list: List<T>): List<Pair<Int, T>> =
list.withIndex().map { it.index to it.value }
Returns a list of pairs built from the elements of the list along with the element at the next index.
fun <T> zipWithNext(list: List<T>): List<Pair<T, T>> =
list.zipWithNext()
Given a list of predicates, returns a single predicate that evaluates to true if all of the predicates evaluate to true, and false otherwise.
fun <T> allOf(vararg predicates: (T) -> Boolean): (T) -> Boolean =
{ t -> predicates.all { it(t) } }
Returns a function which first applies this
function to the input, and then applies the after
function to the result.
// For example:
String::decapitalize andThen String::hashCode
infix fun <T, U, R> ((T) -> U).andThen(after: (U) -> R): (T) -> R = { after(this(it)) }
Given a list of predicates, returns a single predicate that evaluates to true if any of the predicates evaluate to true, and false otherwise.
fun <T> anyOf(vararg predicates: (T) -> Boolean): (T) -> Boolean =
{ t -> predicates.any { it(t) } }
Applies the first argument of a curried function, returning a function taking 1 less argument.
fun <T, U, R> applyFirst(function: (T) -> (U) -> R, first: T): (U) -> R = function(first)
Applies the second argument of a curried function, returning a function taking 1 less argument.
fun <T, U, R> applySecond(function: (T) -> (U) -> R, second: U): (T) -> R = { t -> function(t)(second) }
Returns a function which first applies the before
function to the input, and then applies this
function to the result.
// For example:
String::hashCode compose String::decapitalize
infix fun <T, U, V> ((U) -> V).compose(before: (T) -> U): (T) -> V = { this(before(it)) }
Returns a function which always evaluates to the same result, no matter the input.
fun <T, R> constant(result: R): (T) -> R = { result }
Transforms a function that takes multiple arguments into one that takes a single argument - and returns another function also taking a single argument.
fun <T, U, R> ((T, U) -> R).curry(): (T) -> (U) -> R = { t -> { u -> this(t, u) } }
Tests a value against a predicate and executes either the success function or failure function.
fun <T, R> diverge(t: T, predicate: (T) -> Boolean, onSuccess: (T) -> R, onFailure: (T) -> R): R =
if (predicate(t)) onSuccess(t) else onFailure(t)
Returns a function that always returns its input argument.
fun <T> identity(): (T) -> T = { it }
Returns a predicate that tests if an object is equal to at least one of the given values.
// For example:
val is123 = isIn(1, 2, 3)
is123(1) // true
is123(4) // false
fun <T> isIn(vararg values: (T)): (T) -> Boolean =
{ t -> values.any { it == t } }
Takes a function operating on raw values and lifts it to a function operating on Result
values.
fun <T, U, R> lift(function: (T) -> (U) -> R): (Result<T>) -> (Result<U>) -> Result<R> =
{ resultT -> { resultU -> resultT.mapCatching(function).mapCatching { resultU.map(it) }.mapCatching { it.getOrThrow() } } }
Returns a memoized version of the given function - the function now caches all of its results.
fun <T, R> memoize(function: (T) -> R): (T) -> R =
with(ConcurrentHashMap<T, R>()) {
{ t -> computeIfAbsent(t) { function(it) } }
}
Given a list of predicates, returns a single predicate that evaluates to true if none of the predicates evaluate to true, and false otherwise.
fun <T> noneOf(vararg predicates: (T) -> Boolean): (T) -> Boolean =
{ t -> !predicates.any { it(t) } }
Returns a retrying version of the given function.
This implementation is based on Pierre-Yves Saumont's implementation in The Joy of Kotlin
fun <T, R> retry(times: Int, delay: Duration, function: (T) -> R): (T) -> Result<R> {
tailrec fun retry(input: T, result: Result<R>, times: Int): () -> Result<R> {
if (result.isSuccess || times <= 0) {
return { result }
} else {
Thread.sleep(delay.toMillis())
return retry(input, runCatching { function(input) }, times - 1)
}
}
return { t -> retry(t, runCatching { function(t) }, times - 1)() }
}
Reduces many functions into a single function which produces a list.
fun <T, R> sequence(list: List<(T) -> R>): (T) -> List<R> = { t -> list.map { it(t) } }
Swaps the arguments of a curried function.
fun <T, U, R> ((T) -> (U) -> R).swapArgs(): (U) -> (T) -> R = { u -> { t -> this(t)(u) } }
Times a function and returns the time as well as the result.
fun <R> time(function: () -> R): Pair<Duration, Result<R>> {
val start = System.nanoTime()
val result = runCatching(function)
val time = System.nanoTime() - start
return Duration.ofNanos(time) to result
}
Transforms a series of single argument functions into a single function with multiple arguments.
fun <T, U, R> ((T) -> (U) -> R).uncurry(): (T, U) -> R = { t, u -> this(t)(u) }
Takes a function operating on Result
values and unlifts it to one operating on raw values.
fun <T, U, R> unlift(function: (Result<T>) -> (Result<U>) -> Result<R>): (T) -> (U) -> R =
{ t -> { u -> function(Result.success(t))(Result.success(u)).getOrThrow() } }
Transforms a lazy value into a lazy list, i.e. a Sequence.
fun <T> Lazy<T>.asSequence(): Sequence<T> = sequence { yield(value) }
Evaluates a predicate against the value produced by the Lazy and returns a successful Result if the predicate evaluates to true, or a failure Result otherwise.
fun <T> Lazy<T>.filter(predicate: (T) -> Boolean): Lazy<Result<T>> =
lazy { if (predicate(value)) Result.success(value) else Result.failure(IllegalArgumentException("Predicate evaluated to false.")) }
Applies a function that produces a Lazy to the value produced by this
Lazy.
fun <T, R> Lazy<T>.flatMap(function: (T) -> Lazy<R>): Lazy<R> =
lazy { function(value).value }
Returns an infinite lazy list, i.e. a Sequence, which always produces the given lazy's value.
fun <T> Lazy<T>.forever(): Sequence<T> = object : Iterator<T> {
override fun hasNext(): Boolean = true
override fun next(): T = value
}.asSequence()
Safely gets the value produced by this
Lazy and optionally returns the default value if any exception is thrown by the Lazy.
The initialization of the value produced by a Lazy may throw an exception, this method guarantees that no exceptions are thrown while initializing that value.
fun <R, T : R> Lazy<T>.getOrDefault(default: R): R =
runCatching { value }.getOrDefault(default)
Takes a function operating on raw values and lifts it to a function operating on Lazy values.
fun <T, U, R> lift(function: (T) -> (U) -> R): (Lazy<T>) -> (Lazy<U>) -> Lazy<R> =
{ lazyT -> { lazyU -> lazy { function(lazyT.value)(lazyU.value) } } }
Applies a function to the value produced by this
Lazy.
fun <T, R> Lazy<T>.map(function: (T) -> R): Lazy<R> =
lazy { function(value) }
Applies a function taking 2 raw values to 2 values produced by Lazys, and returns another Lazy.
fun <T, U, R> map2(lazy1: Lazy<T>, lazy2: Lazy<U>, function: (T) -> (U) -> R): Lazy<R> =
lazy { function(lazy1.value)(lazy2.value) }
Reduces many Lazys into a single Lazy which produces a list.
fun <T> sequence(list: List<Lazy<T>>): Lazy<List<T>> =
lazy { list.map { it.value } }
Reduces many Lazys into a single Lazy which produces a Result of type list. If any of the passed in Lazys throw an exception the Result will be a failure.
fun <T> sequenceCatching(list: List<Lazy<T>>): Lazy<Result<List<T>>> =
lazy { runCatching { list.map { it.value } } }
Lazily tests the value produced by this
Lazy against a predicate and returns a Lazy boolean.
fun <T> Lazy<T>.test(predicate: (T) -> Boolean): Lazy<Boolean> =
lazy { predicate(value) }
Concatenates multiple maps into a single map, preserving the order of the passed in entries.
Note: there is expensive list concatenation in this snippet.
fun <K, V> merge(first: Map<K, V>, vararg others: Map<K, V>): Map<K, List<V>> =
first.mapValues { entry -> listOf(entry.value) }.toMap(LinkedHashMap()).apply {
others.forEach {
map -> map.forEach { key, value -> merge(key, listOf(value)) { list1, list2 -> list1 + list2 } }
}
}
Picks the map entries which have keys contained in the given list.
fun <K, V> Map<K, V>.pick(list: List<K>): Map<K, V> =
list.toSet().run {
filterKeys { contains(it) }
}
Splits the original map into a pair of maps, where the first map has all entries for which the predicate evaluated to true
, and the second contains all other entries.
fun <K, V> Map<K, V>.split(predicate: (K) -> Boolean): Pair<Map<K, V>, Map<K, V>> =
(HashMap<K, V>() to HashMap<K, V>()).apply {
forEach { key, value -> if (predicate(key)) first.put(key, value) else second.put(key, value) }
}
Given a function, transforms all the values in an enum class into an EnumMap
, where the key is the enum value and the value is the result of applying the function to the enum value.
enum class Stooge { MOE, LARRY, CURLY }
fun main() {
Stooge::class.toEnumMap { it.toString().length }.forEach(::println)
}
inline fun <reified K : Enum<K>, V> KClass<K>.toEnumMap(function: (K) -> V): EnumMap<K, V> =
enumValues<K>().fold(EnumMap(this.java)) { map, key -> map.apply { put(key, function(key)) } }
MIT