对于任何给定的集合,例如,
val fruits = Set("apple", "grape", "pear", "banana")
如何从fruits
获取随机元素?
非常感谢。
答案 0 :(得分:19)
转换为Vector
并从中获取随机元素
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
答案 1 :(得分:17)
因此,之前发布的每个答案都具有复杂度 O(n)的空间,因为它们以某种方式创建了整个集合的副本。这是一个没有任何额外复制的解决方案(因此它是“恒定空间”):
def random[T](s: Set[T]): T = {
val n = util.Random.nextInt(s.size)
s.iterator.drop(n).next
}
答案 2 :(得分:2)
解决方法1
随机方式(import scala.util.Random
)
scala> fruits.toList(Random.nextInt(fruits.size))
res0: java.lang.String = banana
溶液2
数学方式(无进口)
scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana
答案 3 :(得分:2)
您可以使用切片直接访问Set的元素。当我使用的是一个大小正在变化的集合时,我使用了这个,所以每次将它转换为Vector都会有点矫枉过正。
val roll = new Random ()
val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
答案 4 :(得分:1)
import Scala.util.Random
val fruits = Set("apple", "grape", "pear", "banana").toVector
val sz =fruits.size
val num = Random.nextInt(sz)
fruits(num)
答案 5 :(得分:1)
从该问题的其他答案中汲取灵感,我想到了:
private def randomItem[T](items: Traversable[T]): Option[T] = {
val i = Random.nextInt(items.size)
items.view(i, i + 1).headOption
}
这不会复制任何内容,如果Set
(或其他类型的Traversable
)为空,也不会失败,而且一目了然。如果确定Set
不为空,则可以替换.head
并返回T
。
答案 6 :(得分:0)
不将Set
转换为有序集合,但使用zipWithIndex
我们可以将索引归因于集合中的每个项目,
fruits.zipWithIndex
Set((apple,0), (grape,1), (pear,2), (banana,3))
因此val rnd = util.Random.nextInt(fruits.size)
,
fruits.zipWithIndex.find( _._2 == rnd)
Option[(String, Int)] = Some((banana,3))
给出一个空集,
Set[String]().zipWithIndex.find( _._2 == 3)
Option[(String, Int)] = None
答案 7 :(得分:0)
如果您不介意O(n)
解决方案:
import util.Random
// val fruits = Set("apple", "grape", "pear", "banana")
Random.shuffle(fruits).head
// "pear"