Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add baisc Array extensions #15

Merged
merged 1 commit into from
Jan 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,16 @@ byteBuffer.applyIf(shouldReadInt) { getInt() }
#### [Services](src/main/kotlin/pw/forst/katlib/Services.kt)

* `TemporalProvider` - Interface providing access to current time via `now` method, very useful when mocking

#### [Array Extensions](src/main/kotlin/pw/forst/katlib/ArrayExtensions.kt)

* `buildArray(builderAction: MutableList<E>.() -> Unit): Array<E>` - builds a new Array by populating a MutableList using the given builderAction and returning an Array with the same elements
* `Array<out T>.map(transform: (T) -> R): Array<R>` - Returns an array containing the results of applying the given transform function to each element in the original array
* `Array<out T>.mapIndexed(transform: (index: Int, T) -> R): Array<R>` - returns an array containing the results of applying the given transform function to each element and its index in the original array
* `Array<out T>.filter(predicate: (T) -> Boolean): Array<T>` - returns an array containing only elements matching the given predicate
* `Array<out T>.filterNot(predicate: (T) -> Boolean): Array<T>` - returns an array containing all elements not matching the given predicate
* `Array<out T>.filterIndexed(predicate: (index: Int, T) -> Boolean): Array<T>` - returns an array containing only elements matching the given predicate
* `Array<*>.filterIsInstance(): Array<R>` - returns an array containing all elements that are instances of specified type parameter R
* `Array<out T?>.filterNotNull(): Array<T>` - returns an array containing all elements that are not `null`
* `Array<out T>.minus(element: T): Array<T>` - returns an array containing all elements of the original collection without the first occurrence of the given element
* `Array<out T>.minus(elements: Array<out T>): Array<T>` - returns an array containing all elements of the original collection except the elements contained in the given elements array
69 changes: 69 additions & 0 deletions src/main/kotlin/pw/forst/katlib/ArrayExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package pw.forst.katlib

import kotlin.experimental.ExperimentalTypeInference

/**
* Builds a new [Array] by populating a [MutableList] using the given [builderAction]
* and returning an Array with the same elements.
*
* The list passed as a receiver to the [builderAction] is valid only inside that function.
* Using it outside of the function produces an unspecified behavior.
*/
/* It uses BuilderInference just like buildList,
but it can't use buildLists @WasExperimental(ExperimentalStdlibApi::class) annotation because it's kotlin internal*/
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalTypeInference::class)
inline fun <reified E> buildArray(@BuilderInference builderAction: MutableList<E>.() -> Unit) = buildList(builderAction).toTypedArray()

/**
* Returns an array containing the results of applying the given [transform] function
* to each element in the original array.
*/
inline fun <T, reified R> Array<out T>.map(transform: (T) -> R) = mapTo(ArrayList(size), transform).toTypedArray()

/**
* Returns an array containing the results of applying the given [transform] function
* to each element and its index in the original array.
* @param [transform] function that takes the index of an element and the element itself
* and returns the result of the transform applied to the element.
*/
inline fun <T, reified R> Array<out T>.mapIndexed(transform: (index: Int, T) -> R) = mapIndexedTo(ArrayList(size), transform).toTypedArray()

/**
* Returns an array containing only elements matching the given [predicate].
*/
inline fun <reified T> Array<out T>.filter(predicate: (T) -> Boolean) = filterTo(ArrayList(), predicate).toTypedArray()

/**
* Returns an array containing all elements not matching the given [predicate].
*/
inline fun <reified T> Array<out T>.filterNot(predicate: (T) -> Boolean) = filterNotTo(ArrayList(), predicate).toTypedArray()

/**
* Returns an array containing only elements matching the given [predicate].
* @param [predicate] function that takes the index of an element and the element itself
* and returns the result of predicate evaluation on the element.
*/
inline fun <reified T> Array<out T>.filterIndexed(predicate: (index: Int, T) -> Boolean) =
filterIndexedTo(ArrayList(), predicate).toTypedArray()

/**
* Returns an array containing all elements that are instances of specified type parameter R.
*/
inline fun <reified R> Array<*>.filterIsInstance() = filterIsInstanceTo(ArrayList<R>()).toTypedArray()

/**
* Returns an array containing all elements that are not `null`.
*/
inline fun <reified T : Any> Array<out T?>.filterNotNull() = filterNotNullTo(ArrayList<T>()).toTypedArray()

/**
* Returns an array containing all elements of the original collection without the first occurrence of the given [element].
*/
inline operator fun <reified T> Array<out T>.minus(element: T) = asList<T>().minus(element).toTypedArray()

/**
* Returns an array containing all elements of the original collection except the elements contained in the given [elements] array.
*/
@Suppress("ConvertArgumentToSet")
inline operator fun <reified T> Array<out T>.minus(elements: Array<out T>) = asList<T>().minus(elements).toTypedArray()
84 changes: 84 additions & 0 deletions src/test/kotlin/pw/forst/katlib/ArrayExtensionsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package pw.forst.katlib

import kotlin.test.Test
import kotlin.test.assertContentEquals

class ArrayExtensionsTest {

@Test
fun `buildArray Test`() {
val builtArray = buildArray {
for (i in 0 until 100) {
add(i)
}
}
val constructedArray = Array(100) { it }
assertContentEquals(builtArray, constructedArray)
}

@Test
fun `Array map Test`() {
val mappedArray = Array(100) { it }.map { it * 2 }
val constructedArray = Array(100) { it * 2 }
assertContentEquals(mappedArray, constructedArray)
}

@Test
fun `Array mapIndexed Test`() {
val mappedArray = Array(100) { 0 }.mapIndexed { index: Int, _: Int -> index }
val constructedArray = Array(100) { it }
assertContentEquals(mappedArray, constructedArray)
}

@Test
fun `Array filter Test`() {
val filteredArray = Array(100) { it }.filter { it % 2 == 0 }
val constructedArray = Array(50) { it * 2 }
assertContentEquals(filteredArray, constructedArray)
}

@Test
fun `Array filterNot Test`() {
val filteredArray = Array(100) { it }.filterNot { it % 2 != 0 }
val constructedArray = Array(50) { it * 2 }
assertContentEquals(filteredArray, constructedArray)
}

@Test
fun `Array filterIndexed Test`() {
val filteredArray = Array(100) { it }.filterIndexed { index, _ -> index % 2 == 0 }
val constructedArray = Array(50) { it * 2 }
assertContentEquals(filteredArray, constructedArray)
}

@Test
fun `Array filterIsInstance Test`() {
val filteredArray = arrayOf<Number>(0, 1, 0f, 0.0, 1L).filterIsInstance<Int>()
val constructedArray = Array(2) { it }
assertContentEquals(filteredArray, constructedArray)
}

@Test
fun `Array filterNotNull Test`() {
val filteredArray = arrayOf(null, 0, 1, null).filterNotNull()
val constructedArray = Array(2) { it }
assertContentEquals(filteredArray, constructedArray)
}

@Test
fun `Array minus element Test`()
{
val arrayA = Array(100) { it }
val arrayB = Array(100) { it + 200}
val combinedArray = arrayA + arrayB
assertContentEquals(arrayA, combinedArray - arrayB)
}

@Test
fun `Array minus elements Test`()
{
val arrayA = Array(5){it}
val arrayB = Array(4){it}
assertContentEquals(arrayA - 4, arrayB)
}
}