How to get a random element from a Set in Scala

大兔子大兔子 提交于 2019-12-21 03:18:16

问题


For any given set, for instance,

val fruits = Set("apple", "grape", "pear", "banana")

how to get a random element from fruits ?

Many Thanks.


回答1:


convert into Vector and get random element from it

scala> val fruits = Set("apple", "grape", "pear", "banana")
fruits: scala.collection.immutable.Set[String] = Set(apple, grape, pear, banana)

scala> import scala.util.Random
import scala.util.Random

scala> val rnd=new Random
rnd: scala.util.Random = scala.util.Random@31a9253

scala> fruits.toVector(rnd.nextInt(fruits.size))
res8: String = apple



回答2:


So, every answer posted before has complexity O(n) in terms of space, since they create a copy a whole collection in some way. Here is a solution without any additional copying (therefore it is "constant space"):

def random[T](s: Set[T]): T = {
  val n = util.Random.nextInt(s.size)
  s.iterator.drop(n).next
}



回答3:


You can directly access an element of a Set with slice. I used this when I was working with a set that was changing in size, so converting it to a Vector every time seemed like overkill.

val roll = new Random ()

val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last



回答4:


Solution1

Random way ( import scala.util.Random )

scala>  fruits.toList(Random.nextInt(fruits.size))
res0: java.lang.String = banana

Solution2

Math way (no imports)

scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana



回答5:


   import Scala.util.Random

   val fruits = Set("apple", "grape", "pear", "banana").toVector

   val sz =fruits.size

   val num = Random.nextInt(sz)

   fruits(num)



回答6:


Drawing inspiration from the other answers to this question, I've come up with:

private def randomItem[T](items: Traversable[T]): Option[T] = {
  val i = Random.nextInt(items.size)
  items.view(i, i + 1).headOption
}

This doesn't copy anything, doesn't fail if the Set (or other type of Traversable) is empty, and it's clear at a glance what it does. If you're certain that the Set is not empty, you could substitute .head and return T instead.




回答7:


Not converting the Set to an ordered collection but using zipWithIndex we can attribute an index to each item in the collection,

fruits.zipWithIndex
Set((apple,0), (grape,1), (pear,2), (banana,3))

Thus for val rnd = util.Random.nextInt(fruits.size),

fruits.zipWithIndex.find( _._2 == rnd)
Option[(String, Int)] = Some((banana,3))

Given an empty set,

Set[String]().zipWithIndex.find( _._2 == 3)
Option[(String, Int)] = None



回答8:


If you don't mind an O(n) solution:

import util.Random

// val fruits = Set("apple", "grape", "pear", "banana")
Random.shuffle(fruits).head
// "pear"


来源:https://stackoverflow.com/questions/25053724/how-to-get-a-random-element-from-a-set-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!