humazed
humazed

Reputation: 76942

Get a random item from list using kotlin streams

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

Answers (6)

Willi Mentzel
Willi Mentzel

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

Ivan Strelka
Ivan Strelka

Reputation: 1

fun <E> List<E>.getRandomListElements(): List<E>? = if (isNotEmpty()) this.shuffled().take(Random.nextInt(size)) else null

Upvotes: 0

Valentin Michalak
Valentin Michalak

Reputation: 2147

Kotlin 1.3 and above:

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())
}

Try it online!

or in your case

fun main() {
    val list = (1..9).filter { it % 2 == 0 }
    println(list.random())
}

Try it online!


Kotlin 1.2

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

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.

JVM

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

JS

On the JS, we use Math.Random.

fun IntRange.random() = (Math.random() * ((endInclusive + 1) - start) + start).toInt()

Upvotes: 68

Giszmo
Giszmo

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

hardiBSalih
hardiBSalih

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

humazed
humazed

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

Related Questions