Extension random() to select random element from a collection

Fixes #KT-15539
This commit is contained in:
Ilya Gorbunov
2018-08-24 06:12:50 +03:00
parent b0bcd78e38
commit ea2c33a532
20 changed files with 652 additions and 3 deletions
@@ -1604,6 +1604,15 @@ public final class kotlin/collections/ArraysKt {
public static final fun plus ([ZLjava/util/Collection;)[Z
public static final fun plus ([ZZ)[Z
public static final fun plus ([Z[Z)[Z
public static final fun random ([BLkotlin/random/Random;)B
public static final fun random ([CLkotlin/random/Random;)C
public static final fun random ([DLkotlin/random/Random;)D
public static final fun random ([FLkotlin/random/Random;)F
public static final fun random ([ILkotlin/random/Random;)I
public static final fun random ([JLkotlin/random/Random;)J
public static final fun random ([Ljava/lang/Object;Lkotlin/random/Random;)Ljava/lang/Object;
public static final fun random ([SLkotlin/random/Random;)S
public static final fun random ([ZLkotlin/random/Random;)Z
public static final fun reduce ([BLkotlin/jvm/functions/Function2;)B
public static final fun reduce ([CLkotlin/jvm/functions/Function2;)C
public static final fun reduce ([DLkotlin/jvm/functions/Function2;)D
@@ -2234,6 +2243,7 @@ public final class kotlin/collections/CollectionsKt {
public static final fun plus (Ljava/util/Collection;Ljava/lang/Object;)Ljava/util/List;
public static final fun plus (Ljava/util/Collection;Lkotlin/sequences/Sequence;)Ljava/util/List;
public static final fun plus (Ljava/util/Collection;[Ljava/lang/Object;)Ljava/util/List;
public static final fun random (Ljava/util/Collection;Lkotlin/random/Random;)Ljava/lang/Object;
public static final fun reduce (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static final fun reduceIndexed (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object;
public static final fun reduceRight (Ljava/util/List;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
@@ -2493,6 +2503,10 @@ public final class kotlin/collections/UArraysKt {
public static final fun contentToString-3o8tnvbt ([J)Ljava/lang/String;
public static final fun contentToString-9gu3s6ig ([S)Ljava/lang/String;
public static final fun contentToString-doljm8k0 ([I)Ljava/lang/String;
public static final fun random-25eqzsg0 ([JLkotlin/random/Random;)J
public static final fun random-8tx9e8n3 ([BLkotlin/random/Random;)B
public static final fun random-9uc5g3in ([SLkotlin/random/Random;)S
public static final fun random-bunzpqo3 ([ILkotlin/random/Random;)I
public static final fun toTypedArray-1biuymyp ([B)[Lkotlin/UByte;
public static final fun toTypedArray-3o8tnvbt ([J)[Lkotlin/ULong;
public static final fun toTypedArray-9gu3s6ig ([S)[Lkotlin/UShort;
@@ -4125,6 +4139,9 @@ public final class kotlin/ranges/RangesKt {
public static final fun longRangeContains (Lkotlin/ranges/ClosedRange;F)Z
public static final fun longRangeContains (Lkotlin/ranges/ClosedRange;I)Z
public static final fun longRangeContains (Lkotlin/ranges/ClosedRange;S)Z
public static final fun random (Lkotlin/ranges/CharRange;Lkotlin/random/Random;)C
public static final fun random (Lkotlin/ranges/IntRange;Lkotlin/random/Random;)I
public static final fun random (Lkotlin/ranges/LongRange;Lkotlin/random/Random;)J
public static final fun rangeTo (DD)Lkotlin/ranges/ClosedFloatingPointRange;
public static final fun rangeTo (FF)Lkotlin/ranges/ClosedFloatingPointRange;
public static final fun rangeTo (Ljava/lang/Comparable;Ljava/lang/Comparable;)Lkotlin/ranges/ClosedRange;
@@ -4235,6 +4252,8 @@ public final class kotlin/ranges/URangesKt {
public static final fun downTo-2ccbonl2 (BB)Lkotlin/ranges/UIntProgression;
public static final fun downTo-6o7e3yo2 (JJ)Lkotlin/ranges/ULongProgression;
public static final fun downTo-cjsx449s (SS)Lkotlin/ranges/UIntProgression;
public static final fun random (Lkotlin/ranges/UIntRange;Lkotlin/random/Random;)I
public static final fun random (Lkotlin/ranges/ULongRange;Lkotlin/random/Random;)J
public static final fun reversed (Lkotlin/ranges/UIntProgression;)Lkotlin/ranges/UIntProgression;
public static final fun reversed (Lkotlin/ranges/ULongProgression;)Lkotlin/ranges/ULongProgression;
public static final fun step (Lkotlin/ranges/UIntProgression;I)Lkotlin/ranges/UIntProgression;
@@ -4934,6 +4953,7 @@ public final class kotlin/text/StringsKt {
public static final fun partition (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lkotlin/Pair;
public static final fun prependIndent (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
public static synthetic fun prependIndent$default (Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;
public static final fun random (Ljava/lang/CharSequence;Lkotlin/random/Random;)C
public static final fun reduce (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)C
public static final fun reduceIndexed (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)C
public static final fun reduceRight (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)C
@@ -13,6 +13,17 @@ object Elements : TemplateGroupBase() {
init {
defaultBuilder {
sequenceClassification(terminal)
specialFor(ArraysOfUnsigned) {
since("1.3")
annotation("@ExperimentalUnsignedTypes")
}
specialFor(RangesOfPrimitives) {
if (primitive in PrimitiveType.unsignedPrimitives) {
since("1.3")
annotation("@ExperimentalUnsignedTypes")
sourceFile(SourceFile.URanges)
}
}
}
}
@@ -808,6 +819,69 @@ object Elements : TemplateGroupBase() {
}
}
val f_random = fn("random()") {
include(Collections, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences, RangesOfPrimitives)
} builder {
since("1.3")
inlineOnly()
returns("T")
doc {
"""
Returns a random ${f.element} from this ${f.collection}.
@throws ${if (f == RangesOfPrimitives) "IllegalArgumentException" else "NoSuchElementException"} if this ${f.collection} is empty.
"""
}
body {
"""return random(Random)"""
}
}
val f_random_random = fn("random(random: Random)") {
include(Collections, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences, RangesOfPrimitives)
} builder {
since("1.3")
returns("T")
doc {
"""
Returns a random ${f.element} from this ${f.collection} using the specified source of randomness.
@throws ${if (f == RangesOfPrimitives) "IllegalArgumentException" else "NoSuchElementException"} if this ${f.collection} is empty.
"""
}
body {
"""
if (isEmpty())
throw NoSuchElementException("${f.doc.collection.capitalize()} is empty.")
return elementAt(random.nextInt(size))
"""
}
specialFor(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) {
body {
val size = if (family == CharSequences) "length" else "size"
"""
if (isEmpty())
throw NoSuchElementException("${f.doc.collection.capitalize()} is empty.")
return get(random.nextInt($size))
"""
}
}
specialFor(Maps) {
body {
"""return entries.random(random)"""
}
}
specialFor(RangesOfPrimitives) {
body {
val expr = when (primitive) {
PrimitiveType.Char -> "nextInt(first.toInt(), last.toInt() + 1).toChar()"
else -> "next$primitive(this)"
}
"""return random.$expr"""
}
}
}
val f_components = (1..5).map { n ->
fn("component$n()") {
include(Lists, ArraysOfObjects, ArraysOfPrimitives)
@@ -10,7 +10,7 @@ import templates.PrimitiveType.Companion.maxByCapacity
object RangeOps : TemplateGroupBase() {
private val rangePrimitives = setOf(PrimitiveType.Int, PrimitiveType.Long, PrimitiveType.Char, PrimitiveType.UInt, PrimitiveType.ULong)
private val rangePrimitives = PrimitiveType.rangePrimitives
private fun rangeElementType(fromType: PrimitiveType, toType: PrimitiveType) =
maxByCapacity(fromType, toType).let {
when {
@@ -60,6 +60,7 @@ enum class PrimitiveType {
val defaultPrimitives = PrimitiveType.values().toSet() - unsignedPrimitives
val numericPrimitives = setOf(Int, Long, Byte, Short, Double, Float)
val integralPrimitives = setOf(Int, Long, Byte, Short, Char)
val rangePrimitives = setOf(Int, Long, Char, UInt, ULong)
val descendingByDomainCapacity = listOf(Double, Float, Long, Int, Short, Char, Byte)
val descendingByDomainCapacityUnsigned = listOf(ULong, UInt, UShort, UByte)
@@ -32,8 +32,9 @@ object DocExtensions {
val Family.collection: String
get() = when (this) {
CharSequences -> "char sequence"
ArraysOfObjects, ArraysOfPrimitives, InvariantArraysOfObjects -> "array"
Strings, Sequences, Maps, Lists, Sets, Ranges -> name.singularize().decapitalize()
ArraysOfObjects, ArraysOfPrimitives, InvariantArraysOfObjects, ArraysOfUnsigned -> "array"
Ranges, RangesOfPrimitives -> "range"
Strings, Sequences, Maps, Lists, Sets -> name.singularize().decapitalize()
else -> "collection"
}
@@ -149,6 +149,7 @@ abstract class MemberTemplateDefinition<TParam> : MemberTemplate {
private fun defaultPrimitives(f: Family): Set<PrimitiveType> =
when {
f == Family.Unsigned || f == Family.ArraysOfUnsigned -> PrimitiveType.unsignedPrimitives
f == Family.RangesOfPrimitives -> PrimitiveType.rangePrimitives
f.isPrimitiveSpecialization -> PrimitiveType.defaultPrimitives
else -> emptySet()
}
@@ -92,6 +92,9 @@ fun List<MemberBuilder>.writeTo(file: File, platformSource: PlatformSourceFile)
writer.appendln("import kotlin.*")
writer.appendln("import kotlin.text.*")
writer.appendln("import kotlin.comparisons.*")
if (platform == Platform.Common) {
writer.appendln("import kotlin.random.*")
}
if (sourceFile == SourceFile.Sequences) {
writer.appendln("import kotlin.coroutines.experimental.*")