Provide minus and minusAssign for iterables, collections, sets, sequences.
removeAll and retainAll special case optimizations. #KT-3721 Fixed #KT-7466 Fixed
This commit is contained in:
@@ -381,6 +381,140 @@ public fun <T, R, V> Sequence<T>.merge(sequence: Sequence<R>, transform: (T, R)
|
||||
return MergingSequence(this, sequence, transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements of the original collection except the elements contained in the given [array].
|
||||
*/
|
||||
public fun <T> Iterable<T>.minus(array: Array<out T>): List<T> {
|
||||
if (array.isEmpty()) return this.toList()
|
||||
val other = array.toHashSet()
|
||||
return this.filterNot { it in other }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing all elements of original sequence except the elements contained in the given [array].
|
||||
*/
|
||||
public fun <T> Sequence<T>.minus(array: Array<out T>): Sequence<T> {
|
||||
if (array.isEmpty()) return this
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = array.toHashSet()
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing all elements of the original set except the elements contained in the given [array].
|
||||
*/
|
||||
public fun <T> Set<T>.minus(array: Array<out T>): Set<T> {
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(array)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements of the original collection except the elements contained in the given [collection].
|
||||
*/
|
||||
public fun <T> Iterable<T>.minus(collection: Iterable<T>): List<T> {
|
||||
val other = collection.convertToSetForSetOperationWith(this)
|
||||
if (other.isEmpty())
|
||||
return this.toList()
|
||||
return this.filterNot { it in other }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing all elements of original sequence except the elements contained in the given [collection].
|
||||
*/
|
||||
public fun <T> Sequence<T>.minus(collection: Iterable<T>): Sequence<T> {
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = collection.convertToSetForSetOperation()
|
||||
if (other.isEmpty())
|
||||
return this@minus.iterator()
|
||||
else
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing all elements of the original set except the elements contained in the given [collection].
|
||||
*/
|
||||
public fun <T> Set<T>.minus(collection: Iterable<T>): Set<T> {
|
||||
val other = collection.convertToSetForSetOperationWith(this)
|
||||
if (other.isEmpty())
|
||||
return this.toSet()
|
||||
if (other is Set)
|
||||
return this.filterNotTo(LinkedHashSet<T>()) { it in other }
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(other)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements of the original collection without the first occurrence of the given [element].
|
||||
*/
|
||||
public fun <T> Iterable<T>.minus(element: T): List<T> {
|
||||
val result = ArrayList<T>(collectionSizeOrDefault(10))
|
||||
var removed = false
|
||||
return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing all elements of the original sequence without the first occurrence of the given [element].
|
||||
*/
|
||||
public fun <T> Sequence<T>.minus(element: T): Sequence<T> {
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
var removed = false
|
||||
return this@minus.filter { if (!removed && it == element) { removed = true; false } else true }.iterator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing all elements of the original set except the given [element].
|
||||
*/
|
||||
public fun <T> Set<T>.minus(element: T): Set<T> {
|
||||
val result = LinkedHashSet<T>(mapCapacity(size()))
|
||||
var removed = false
|
||||
return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements of the original collection except the elements contained in the given [sequence].
|
||||
*/
|
||||
public fun <T> Iterable<T>.minus(sequence: Sequence<T>): List<T> {
|
||||
val other = sequence.toHashSet()
|
||||
if (other.isEmpty())
|
||||
return this.toList()
|
||||
return this.filterNot { it in other }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing all elements of original sequence except the elements contained in the given [sequence].
|
||||
*/
|
||||
public fun <T> Sequence<T>.minus(sequence: Sequence<T>): Sequence<T> {
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = sequence.toHashSet()
|
||||
if (other.isEmpty())
|
||||
return this@minus.iterator()
|
||||
else
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing all elements of the original set except the elements contained in the given [sequence].
|
||||
*/
|
||||
public fun <T> Set<T>.minus(sequence: Sequence<T>): Set<T> {
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(sequence)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits original collection into pair of collections,
|
||||
* where *first* collection contains elements for which [predicate] yielded `true`,
|
||||
|
||||
@@ -126,4 +126,27 @@ public fun <T> Iterable<T>.collectionSizeOrNull(): Int? = if (this is Collection
|
||||
/**
|
||||
* Returns the size of this iterable if it is known, or the specified [default] value otherwise.
|
||||
*/
|
||||
public fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) size() else default
|
||||
public fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) size() else default
|
||||
|
||||
/** Returns true when it's safe to convert this collection to a set without changing contains method behavior. */
|
||||
private fun <T> Collection<T>.safeToConvertToSet() = size() > 2 && this is ArrayList
|
||||
|
||||
/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */
|
||||
private fun <T> Iterable<T>.convertToSetForSetOperationWith(source: Iterable<T>): Collection<T> =
|
||||
when(this) {
|
||||
is Set -> this
|
||||
is Collection ->
|
||||
when {
|
||||
source is Collection && source.size() < 2 -> this
|
||||
else -> if (this.safeToConvertToSet()) toHashSet() else this
|
||||
}
|
||||
else -> toHashSet()
|
||||
}
|
||||
|
||||
/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */
|
||||
private fun <T> Iterable<T>.convertToSetForSetOperation(): Collection<T> =
|
||||
when(this) {
|
||||
is Set -> this
|
||||
is Collection -> if (this.safeToConvertToSet()) toHashSet() else this
|
||||
else -> toHashSet()
|
||||
}
|
||||
|
||||
@@ -28,6 +28,34 @@ public fun <T> MutableCollection<in T>.plusAssign(sequence: Sequence<T>) {
|
||||
this.addAll(sequence)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a single instance of the specified [element] from this mutable collection.
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.minusAssign(element: T) {
|
||||
this.remove(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements contained in the given [collection] from this mutable collection.
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.minusAssign(collection: Iterable<T>) {
|
||||
this.removeAll(collection)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements contained in the given [array] from this mutable collection.
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.minusAssign(array: Array<T>) {
|
||||
this.removeAll(array)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements contained in the given [sequence] from this mutable collection.
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.minusAssign(sequence: Sequence<T>) {
|
||||
this.removeAll(sequence)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all elements of the given [iterable] to this [MutableCollection].
|
||||
*/
|
||||
@@ -56,46 +84,53 @@ public fun <T> MutableCollection<in T>.addAll(array: Array<out T>) {
|
||||
* Removes all elements from this [MutableCollection] that are also contained in the given [iterable].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.removeAll(iterable: Iterable<T>) {
|
||||
when (iterable) {
|
||||
is Collection -> removeAll(iterable)
|
||||
else -> removeAll(iterable.toHashSet())
|
||||
}
|
||||
removeAll(iterable.convertToSetForSetOperationWith(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from this [MutableCollection] that are also contained in the given [sequence].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.removeAll(sequence: Sequence<T>) {
|
||||
removeAll(sequence.toHashSet())
|
||||
val set = sequence.toHashSet()
|
||||
if (set.isNotEmpty())
|
||||
removeAll(set)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from this [MutableCollection] that are also contained in the given [array].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.removeAll(array: Array<out T>) {
|
||||
removeAll(array.toHashSet())
|
||||
if (array.isNotEmpty())
|
||||
removeAll(array.toHashSet())
|
||||
// else
|
||||
// removeAll(emptyList())
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only elements of this [MutableCollection] that are contained in the given [iterable].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.retainAll(iterable: Iterable<T>) {
|
||||
when (iterable) {
|
||||
is Collection -> retainAll(iterable)
|
||||
else -> retainAll(iterable.toHashSet())
|
||||
}
|
||||
retainAll(iterable.convertToSetForSetOperationWith(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only elements of this [MutableCollection] that are contained in the given [array].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.retainAll(array: Array<out T>) {
|
||||
retainAll(array.toHashSet())
|
||||
if (array.isNotEmpty())
|
||||
retainAll(array.toHashSet())
|
||||
else
|
||||
clear()
|
||||
// retainAll(emptyList())
|
||||
}
|
||||
|
||||
/**
|
||||
* Retains only elements of this [MutableCollection] that are contained in the given [sequence].
|
||||
*/
|
||||
public fun <T> MutableCollection<in T>.retainAll(sequence: Sequence<T>) {
|
||||
retainAll(sequence.toHashSet())
|
||||
val set = sequence.toHashSet()
|
||||
if (set.isNotEmpty())
|
||||
retainAll(set)
|
||||
else
|
||||
clear()
|
||||
}
|
||||
|
||||
@@ -177,6 +177,163 @@ fun generators(): List<GenericFunction> {
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("minus(element: T)") {
|
||||
only(Iterables, Sets, Sequences)
|
||||
doc { "Returns a list containing all elements of the original collection without the first occurrence of the given [element]." }
|
||||
returns("List<T>")
|
||||
body {
|
||||
"""
|
||||
val result = ArrayList<T>(collectionSizeOrDefault(10))
|
||||
var removed = false
|
||||
return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true }
|
||||
"""
|
||||
}
|
||||
|
||||
returns("SELF", Sets, Sequences)
|
||||
doc(Sets) { "Returns a set containing all elements of the original set except the given [element]." }
|
||||
body(Sets) {
|
||||
"""
|
||||
val result = LinkedHashSet<T>(mapCapacity(size()))
|
||||
var removed = false
|
||||
return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true }
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
doc(Sequences) { "Returns a sequence containing all elements of the original sequence without the first occurrence of the given [element]." }
|
||||
body(Sequences) {
|
||||
"""
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
var removed = false
|
||||
return this@minus.filter { if (!removed && it == element) { removed = true; false } else true }.iterator()
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
templates add f("minus(collection: Iterable<T>)") {
|
||||
only(Iterables, Sets, Sequences)
|
||||
doc { "Returns a list containing all elements of the original collection except the elements contained in the given [collection]." }
|
||||
returns("List<T>")
|
||||
returns("SELF", Sets, Sequences)
|
||||
body {
|
||||
"""
|
||||
val other = collection.convertToSetForSetOperationWith(this)
|
||||
if (other.isEmpty())
|
||||
return this.toList()
|
||||
|
||||
return this.filterNot { it in other }
|
||||
"""
|
||||
}
|
||||
|
||||
doc(Sets) { "Returns a set containing all elements of the original set except the elements contained in the given [collection]." }
|
||||
body(Sets) {
|
||||
"""
|
||||
val other = collection.convertToSetForSetOperationWith(this)
|
||||
if (other.isEmpty())
|
||||
return this.toSet()
|
||||
if (other is Set)
|
||||
return this.filterNotTo(LinkedHashSet<T>()) { it in other }
|
||||
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(other)
|
||||
return result
|
||||
"""
|
||||
}
|
||||
|
||||
doc(Sequences) { "Returns a sequence containing all elements of original sequence except the elements contained in the given [collection]." }
|
||||
body(Sequences) {
|
||||
"""
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = collection.convertToSetForSetOperation()
|
||||
if (other.isEmpty())
|
||||
return this@minus.iterator()
|
||||
else
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("minus(array: Array<out T>)") {
|
||||
only(Iterables, Sets, Sequences)
|
||||
doc { "Returns a list containing all elements of the original collection except the elements contained in the given [array]." }
|
||||
returns("List<T>")
|
||||
returns("SELF", Sets, Sequences)
|
||||
body {
|
||||
"""
|
||||
if (array.isEmpty()) return this.toList()
|
||||
val other = array.toHashSet()
|
||||
return this.filterNot { it in other }
|
||||
"""
|
||||
}
|
||||
doc(Sets) { "Returns a set containing all elements of the original set except the elements contained in the given [array]." }
|
||||
body(Sets) {
|
||||
"""
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(array)
|
||||
return result
|
||||
"""
|
||||
}
|
||||
|
||||
doc(Sequences) { "Returns a sequence containing all elements of original sequence except the elements contained in the given [array]." }
|
||||
body(Sequences) {
|
||||
"""
|
||||
if (array.isEmpty()) return this
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = array.toHashSet()
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("minus(sequence: Sequence<T>)") {
|
||||
only(Iterables, Sets)
|
||||
doc { "Returns a list containing all elements of the original collection except the elements contained in the given [sequence]." }
|
||||
returns("List<T>")
|
||||
returns("SELF", Sets, Sequences)
|
||||
body {
|
||||
"""
|
||||
val other = sequence.toHashSet()
|
||||
if (other.isEmpty())
|
||||
return this.toList()
|
||||
|
||||
return this.filterNot { it in other }
|
||||
"""
|
||||
}
|
||||
doc(Sets) { "Returns a set containing all elements of the original set except the elements contained in the given [sequence]." }
|
||||
body(Sets) {
|
||||
"""
|
||||
val result = LinkedHashSet<T>(this)
|
||||
result.removeAll(sequence)
|
||||
return result
|
||||
"""
|
||||
}
|
||||
|
||||
doc(Sequences) { "Returns a sequence containing all elements of original sequence except the elements contained in the given [sequence]." }
|
||||
body(Sequences) {
|
||||
"""
|
||||
return object: Sequence<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
val other = sequence.toHashSet()
|
||||
if (other.isEmpty())
|
||||
return this@minus.iterator()
|
||||
else
|
||||
return this@minus.filterNot { it in other }.iterator()
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("partition(predicate: (T) -> Boolean)") {
|
||||
inline(true)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user