Add removeFirst(OrNull) and removeLast(OrNull) methods to MutableList

This commit is contained in:
Abduqodiri Qurbonzoda
2020-01-22 21:20:47 +03:00
parent b6849efd47
commit e459542e6f
3 changed files with 135 additions and 80 deletions
@@ -44,14 +44,6 @@ public inline fun <@kotlin.internal.OnlyInputTypes T> MutableCollection<out T>.r
public inline fun <@kotlin.internal.OnlyInputTypes T> MutableCollection<out T>.retainAll(elements: Collection<T>): Boolean =
@Suppress("UNCHECKED_CAST") (this as MutableCollection<T>).retainAll(elements)
/**
* Removes the element at the specified [index] from this list.
* In Kotlin one should use the [MutableList.removeAt] function instead.
*/
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"), level = DeprecationLevel.ERROR)
@kotlin.internal.InlineOnly
public inline fun <T> MutableList<T>.remove(index: Int): T = removeAt(index)
/**
* Adds the specified [element] to this mutable collection.
*/
@@ -149,71 +141,6 @@ public fun <T> MutableCollection<in T>.addAll(elements: Array<out T>): Boolean {
return addAll(elements.asList())
}
/**
* Removes all elements from this [MutableIterable] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when no elements were removed and collection was not modified.
*/
public fun <T> MutableIterable<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
/**
* Retains only elements of this [MutableIterable] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when all elements were retained and collection was not modified.
*/
public fun <T> MutableIterable<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
private fun <T> MutableIterable<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
var result = false
with(iterator()) {
while (hasNext())
if (predicate(next()) == predicateResultToRemove) {
remove()
result = true
}
}
return result
}
/**
* Removes all elements from this [MutableList] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when no elements were removed and collection was not modified.
*/
public fun <T> MutableList<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
/**
* Retains only elements of this [MutableList] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when all elements were retained and collection was not modified.
*/
public fun <T> MutableList<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
private fun <T> MutableList<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
if (this !is RandomAccess)
return (this as MutableIterable<T>).filterInPlace(predicate, predicateResultToRemove)
var writeIndex: Int = 0
for (readIndex in 0..lastIndex) {
val element = this[readIndex]
if (predicate(element) == predicateResultToRemove)
continue
if (writeIndex != readIndex)
this[writeIndex] = element
writeIndex++
}
if (writeIndex < size) {
for (removeIndex in lastIndex downTo writeIndex)
removeAt(removeIndex)
return true
} else {
return false
}
}
/**
* Removes all elements from this [MutableCollection] that are also contained in the given [elements] collection.
*/
@@ -270,6 +197,117 @@ private fun MutableCollection<*>.retainNothing(): Boolean {
return result
}
/**
* Removes all elements from this [MutableIterable] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when no elements were removed and collection was not modified.
*/
public fun <T> MutableIterable<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
/**
* Retains only elements of this [MutableIterable] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when all elements were retained and collection was not modified.
*/
public fun <T> MutableIterable<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
private fun <T> MutableIterable<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
var result = false
with(iterator()) {
while (hasNext())
if (predicate(next()) == predicateResultToRemove) {
remove()
result = true
}
}
return result
}
/**
* Returns a new list with the elements of this list randomly shuffled
* using the specified [random] instance as the source of randomness.
*/
@SinceKotlin("1.3")
public fun <T> Iterable<T>.shuffled(random: Random): List<T> = toMutableList().apply { shuffle(random) }
/**
* Removes the element at the specified [index] from this list.
* In Kotlin one should use the [MutableList.removeAt] function instead.
*/
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"), level = DeprecationLevel.ERROR)
@kotlin.internal.InlineOnly
public inline fun <T> MutableList<T>.remove(index: Int): T = removeAt(index)
/**
* Removes the first element from this mutable list and returns that removed element, or throws [NoSuchElementException] if this list is empty.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public fun <T> MutableList<T>.removeFirst(): T = if (isEmpty()) throw NoSuchElementException("List is empty.") else removeAt(0)
/**
* Removes the first element from this mutable list and returns that removed element, or returns `null` if this list is empty.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public fun <T> MutableList<T>.removeFirstOrNull(): T? = if (isEmpty()) null else removeAt(0)
/**
* Removes the last element from this mutable list and returns that removed element, or throws [NoSuchElementException] if this list is empty.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public fun <T> MutableList<T>.removeLast(): T = if (isEmpty()) throw NoSuchElementException("List is empty.") else removeAt(lastIndex)
/**
* Removes the last element from this mutable list and returns that removed element, or returns `null` if this list is empty.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public fun <T> MutableList<T>.removeLastOrNull(): T? = if (isEmpty()) null else removeAt(lastIndex)
/**
* Removes all elements from this [MutableList] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when no elements were removed and collection was not modified.
*/
public fun <T> MutableList<T>.removeAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, true)
/**
* Retains only elements of this [MutableList] that match the given [predicate].
*
* @return `true` if any element was removed from this collection, or `false` when all elements were retained and collection was not modified.
*/
public fun <T> MutableList<T>.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false)
private fun <T> MutableList<T>.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean {
if (this !is RandomAccess)
return (this as MutableIterable<T>).filterInPlace(predicate, predicateResultToRemove)
var writeIndex: Int = 0
for (readIndex in 0..lastIndex) {
val element = this[readIndex]
if (predicate(element) == predicateResultToRemove)
continue
if (writeIndex != readIndex)
this[writeIndex] = element
writeIndex++
}
if (writeIndex < size) {
for (removeIndex in lastIndex downTo writeIndex)
removeAt(removeIndex)
return true
} else {
return false
}
}
/**
* Randomly shuffles elements in this mutable list using the specified [random] instance as the source of randomness.
*
@@ -285,10 +323,3 @@ public fun <T> MutableList<T>.shuffle(random: Random): Unit {
}
}
/**
* Returns a new list with the elements of this list randomly shuffled
* using the specified [random] instance as the source of randomness.
*/
@SinceKotlin("1.3")
public fun <T> Iterable<T>.shuffled(random: Random): List<T> = toMutableList().apply { shuffle(random) }
@@ -39,6 +39,26 @@ class MutableCollectionTest {
}
}
@Test fun removeFirst() {
val list = mutableListOf("first", "second")
assertEquals("first", list.removeFirst())
assertEquals("second", list.removeFirstOrNull())
assertNull(list.removeFirstOrNull())
assertFailsWith<NoSuchElementException> { list.removeFirst() }
}
@Test fun removeLast() {
val list = mutableListOf("first", "second")
assertEquals("second", list.removeLast())
assertEquals("first", list.removeLastOrNull())
assertNull(list.removeLastOrNull())
assertFailsWith<NoSuchElementException> { list.removeLast() }
}
@Test fun removeAll() {
val content = listOf("foo", "bar", "bar")
val data = listOf("bar")
@@ -2132,6 +2132,10 @@ public final class kotlin/collections/CollectionsKt {
public static final fun removeAll (Ljava/util/Collection;Lkotlin/sequences/Sequence;)Z
public static final fun removeAll (Ljava/util/Collection;[Ljava/lang/Object;)Z
public static final fun removeAll (Ljava/util/List;Lkotlin/jvm/functions/Function1;)Z
public static final fun removeFirst (Ljava/util/List;)Ljava/lang/Object;
public static final fun removeFirstOrNull (Ljava/util/List;)Ljava/lang/Object;
public static final fun removeLast (Ljava/util/List;)Ljava/lang/Object;
public static final fun removeLastOrNull (Ljava/util/List;)Ljava/lang/Object;
public static final fun requireNoNulls (Ljava/lang/Iterable;)Ljava/lang/Iterable;
public static final fun requireNoNulls (Ljava/util/List;)Ljava/util/List;
public static final fun retainAll (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z