diff --git a/libraries/stdlib/src/generated/_Sets.kt b/libraries/stdlib/src/generated/_Sets.kt index c7f901df21c..0b1e92efe14 100644 --- a/libraries/stdlib/src/generated/_Sets.kt +++ b/libraries/stdlib/src/generated/_Sets.kt @@ -11,73 +11,269 @@ import java.util.* import java.util.Collections // TODO: it's temporary while we have java.util.Collections in js /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun Array.distinct(): Set { - return this.toMutableSet() +public fun Array.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun BooleanArray.distinct(): Set { - return this.toMutableSet() +public fun BooleanArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun ByteArray.distinct(): Set { - return this.toMutableSet() +public fun ByteArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun CharArray.distinct(): Set { - return this.toMutableSet() +public fun CharArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun DoubleArray.distinct(): Set { - return this.toMutableSet() +public fun DoubleArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun FloatArray.distinct(): Set { - return this.toMutableSet() +public fun FloatArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun IntArray.distinct(): Set { - return this.toMutableSet() +public fun IntArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun LongArray.distinct(): Set { - return this.toMutableSet() +public fun LongArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun ShortArray.distinct(): Set { - return this.toMutableSet() +public fun ShortArray.distinct(): List { + return this.toMutableSet().toList() } /** - * Returns a set containing all distinct elements from the given collection. + * Returns a list containing only distinct elements from the given collection. + * The elements in the resulting list are in the same order as they were in the source collection. */ -public fun Iterable.distinct(): Set { - return this.toMutableSet() +public fun Iterable.distinct(): List { + return this.toMutableSet().toList() +} + +/** + * Returns a sequence containing only distinct elements from the given sequence. + * The elements in the resulting sequence are in the same order as they were in the source sequence. + */ +public fun Sequence.distinct(): Sequence { + return this.distinctBy { it } +} + + +deprecated("Migrate to using Sequence and respective functions") +/** + * Returns a stream containing only distinct elements from the given stream. + * The elements in the resulting stream are in the same order as they were in the source stream. + */ +public fun Stream.distinct(): Stream { + return this.distinctBy { it } +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun Array.distinctBy(keySelector: (T) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun BooleanArray.distinctBy(keySelector: (Boolean) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun ByteArray.distinctBy(keySelector: (Byte) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun CharArray.distinctBy(keySelector: (Char) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun DoubleArray.distinctBy(keySelector: (Double) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun FloatArray.distinctBy(keySelector: (Float) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun IntArray.distinctBy(keySelector: (Int) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun LongArray.distinctBy(keySelector: (Long) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun ShortArray.distinctBy(keySelector: (Short) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a list containing only distinct elements from the given collection according to the [keySelector]. + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun Iterable.distinctBy(keySelector: (T) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a sequence containing only distinct elements from the given sequence according to the [keySelector]. + * The elements in the resulting sequence are in the same order as they were in the source sequence. + */ +public fun Sequence.distinctBy(keySelector: (T) -> K): Sequence { + return DistinctSequence(this, keySelector) +} + + +deprecated("Migrate to using Sequence and respective functions") +/** + * Returns a stream containing only distinct elements from the given stream according to the [keySelector]. + * The elements in the resulting stream are in the same order as they were in the source stream. + */ +public fun Stream.distinctBy(keySelector: (T) -> K): Stream { + return DistinctStream(this, keySelector) } /** @@ -351,6 +547,26 @@ public fun Iterable.toMutableSet(): MutableSet { } } +/** + * Returns a mutable set containing all distinct elements from the given sequence. + */ +public fun Sequence.toMutableSet(): MutableSet { + val set = LinkedHashSet() + for (item in this) set.add(item) + return set +} + + +deprecated("Migrate to using Sequence and respective functions") +/** + * Returns a mutable set containing all distinct elements from the given stream. + */ +public fun Stream.toMutableSet(): MutableSet { + val set = LinkedHashSet() + for (item in this) set.add(item) + return set +} + /** * Returns a set containing all distinct elements from both collections. */ diff --git a/libraries/stdlib/src/kotlin/collections/Sequence.kt b/libraries/stdlib/src/kotlin/collections/Sequence.kt index 40a28a7cfcf..38b7c80a3a5 100644 --- a/libraries/stdlib/src/kotlin/collections/Sequence.kt +++ b/libraries/stdlib/src/kotlin/collections/Sequence.kt @@ -1,7 +1,7 @@ package kotlin -import java.util.Enumeration -import java.util.NoSuchElementException +import java.util.* +import kotlin.support.AbstractIterator deprecated("Use Sequence instead.") public interface Stream { @@ -481,6 +481,32 @@ public class DropWhileSequence(private val sequence: Sequence, } } +deprecated("Use DistinctSequence instead and remove with streams.") +private class DistinctStream(private val source: Stream, private val keySelector : (T) -> K) : Stream by DistinctSequence(source.toSequence(), keySelector) + +private class DistinctSequence(private val source : Sequence, private val keySelector : (T) -> K) : Sequence { + override fun iterator(): Iterator = DistinctIterator(source.iterator(), keySelector) +} + +private class DistinctIterator(private val source : Iterator, private val keySelector : (T) -> K) : AbstractIterator() { + private val observed = HashSet() + + override fun computeNext() { + while (source.hasNext()) { + val next = source.next() + val key = keySelector(next) + + if (observed.add(key)) { + setNext(next) + return + } + } + + done() + } +} + + /** * A sequence which repeatedly calls the specified [producer] function and returns its return values, until * `null` is returned from [producer]. diff --git a/libraries/stdlib/test/collections/SequenceTest.kt b/libraries/stdlib/test/collections/SequenceTest.kt index f1d9bba76c9..9adbed14915 100644 --- a/libraries/stdlib/test/collections/SequenceTest.kt +++ b/libraries/stdlib/test/collections/SequenceTest.kt @@ -262,6 +262,16 @@ public class SequenceTest { assertEquals(listOf(0, 1, 0, 1, 2), data.flatten().toList()) } + test fun distinct() { + val sequence = fibonacci().dropWhile { it < 10 }.take(20) + assertEquals(listOf(1, 2, 3, 0), sequence.map { it % 4 }.distinct().toList()) + } + + test fun distinctBy() { + val sequence = fibonacci().dropWhile { it < 10 }.take(20) + assertEquals(listOf(13, 34, 55, 144), sequence.distinctBy { it % 4 }.toList()) + } + /* test fun pairIterator() { diff --git a/libraries/stdlib/test/collections/SetOperationsTest.kt b/libraries/stdlib/test/collections/SetOperationsTest.kt index 1d7abd47943..39f1dbe5518 100644 --- a/libraries/stdlib/test/collections/SetOperationsTest.kt +++ b/libraries/stdlib/test/collections/SetOperationsTest.kt @@ -5,8 +5,13 @@ import org.junit.Test as test class SetOperationsTest { test fun distinct() { - assertEquals(listOf(1, 3, 5), listOf(1, 3, 3, 1, 5, 1, 3).distinct().toList()) - assertTrue(listOf().distinct().none()) + assertEquals(listOf(1, 3, 5), listOf(1, 3, 3, 1, 5, 1, 3).distinct()) + assertTrue(listOf().distinct().isEmpty()) + } + + test fun distinctBy() { + assertEquals(listOf("some", "cat", "do"), arrayOf("some", "case", "cat", "do", "dog", "it").distinctBy { it.length() }) + assertTrue(charArrayOf().distinctBy { it }.isEmpty()) } test fun union() { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt index 452a5682a16..5223de46f82 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt @@ -6,7 +6,7 @@ fun sets(): List { val templates = arrayListOf() templates add f("toMutableSet()") { - exclude(Strings, Sequences) + exclude(Strings) doc { "Returns a mutable set containing all distinct elements from the given collection." } returns("MutableSet") body { @@ -24,18 +24,66 @@ fun sets(): List { return set """ } + doc(Sequences) { "Returns a mutable set containing all distinct elements from the given sequence." } + body(Sequences) { + """ + val set = LinkedHashSet() + for (item in this) set.add(item) + return set + """ + } } templates add f("distinct()") { - exclude(Strings, Sequences) - doc { "Returns a set containing all distinct elements from the given collection." } + exclude(Strings) + val collectionDoc = """ + Returns a list containing only distinct elements from the given collection. - returns("Set") + The elements in the resulting list are in the same order as they were in the source collection. + """ + doc { collectionDoc } + + returns("List") + body { "return this.toMutableSet().toList()" } + doc(Sequences) { collectionDoc.replace("list", "sequence").replace("collection", "sequence") } + returns(Sequences) { "Sequence" } + body(Sequences) { "return this.distinctBy { it }" } + } + + templates add f("distinctBy(keySelector: (T) -> K)") { + exclude(Strings) + val collectionDoc = """ + Returns a list containing only distinct elements from the given collection according to the [keySelector]. + + The elements in the resulting list are in the same order as they were in the source collection. + """ + doc { collectionDoc } + + inline(true) + typeParam("K") + returns("List") body { """ - return this.toMutableSet() + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = keySelector(e) + if (set.add(key)) + list.add(e) + } + return list """ } + + inline(false, Sequences) + doc(Sequences) { collectionDoc.replace("list", "sequence").replace("collection", "sequence") } + returns(Sequences) { "Sequence" } + body(Sequences) { + """ + return DistinctSequence(this, keySelector) + """ + } + } templates add f("union(other: Iterable)") {