Reputation: 76942
How to get a random item from a list in an easy and concise way.
ex: if I want to get an even random number from this list that.
val list = listOf(1, 2, 3, 4, 5, 6, 7, 9).filter { it % 2 == 0 }
Note:
I know there are some similar answers in java that solves this problem but I think we can have a more concise way in kotlin.
Upvotes: 51
Views: 43843
Reputation: 29864
Shuffling the whole list just to get a single random number is a waste of performance.
Use random()
instead which was introduced in Kotin 1.3
val randomNumber = listOf(1, 6, 8).random()
For your special use-case it would make sense to first filter the list and choose a random number from the remaining items.
val list = listOf(1, 2, 3, 4, 5, 6, 7, 9)
val randomEvenNumber = list.filter { it % 2 == 0 }.random()
Upvotes: 21
Reputation: 1
fun <E> List<E>.getRandomListElements(): List<E>? = if (isNotEmpty()) this.shuffled().take(Random.nextInt(size)) else null
Upvotes: 0
Reputation: 2147
Kotlin 1.3 is now available with Multiplatform Random Number Generator! You can use it like this :
import kotlin.random.Random
fun main() {
println(Random.nextBoolean())
println(Random.nextInt())
}
or in your case
fun main() {
val list = (1..9).filter { it % 2 == 0 }
println(list.random())
}
Since Kotlin 1.2, we have Iterable.shuffled()
. This method could help you with the use of List.take()
to extract the number of element you want (only one in this example).
val list = (1..9).filter { it % 2 == 0 }
return list.shuffled().take(1)[0]
This method is less optimized than before 1.2 one but it work on multiplatform context. Use the one you need according to your context.
Before Kotlin 1.2, no solution exists on a Multiplatform context to generate Random Number. The most easy solution is to call the Platform Random directly.
On the JVM we use Random
or even ThreadLocalRandom
if we're on JDK > 1.6.
import java.util.Random
fun IntRange.random() = Random().nextInt((endInclusive + 1) - start) + start
On the JS, we use Math.Random
.
fun IntRange.random() = (Math.random() * ((endInclusive + 1) - start) + start).toInt()
Upvotes: 68
Reputation: 2127
As stated by others, list.random()
should do the trick now but if you don't know if the list is empty, .random()
could throw an exception. Short of implementing .randomOrNull()
as an extension function you can also hack it using list.shuffled().firstOrNull()
but beware this is slow for long lists.
The .randomOrNull()
approach:
fun <E> List<E>.randomOrNull(): E? = if (size > 0) random() else null
Upvotes: 2
Reputation: 61
If you want 25 random elements from a list, I do it like this:
var suliTraffic = ArrayList<SuliTraffic>()
var randomsuliTraffic = ArrayList<SuliTraffic>()
// I have add some data to my Array List
randomsuliTraffic.add(new)
// Here i shuffle all the information i have wich is over 400 object
randomsuliTraffic.shuffle()
// now you can just simply get 25 item from this randomsuliTraffic like this
for (i in randomsuliTraffic.take(25)){
suliTraffic.add(i)
}
Now you can find 25 random elements in the suliTraffic
list.
Upvotes: 1
Reputation: 76942
I think the easiest and the most concise way is to create extension function that returns a random element so it can be used this way:
val random = list.random()
the extension function:
/**
* Returns a random element.
*/
fun <E> List<E>.random(): E? = if (size > 0) get(Random().nextInt(size)) else null
thanks to @Francesco comment here is another function that takes a Random instance as the source of randomness
/**
* Returns a random element using the specified [random] instance as the source of randomness.
*/
fun <E> List<E>.random(random: java.util.Random): E? = if (size > 0) get(random.nextInt(size)) else null
Upvotes: 31