【发布时间】:2011-06-30 09:50:35
【问题描述】:
例如,有一个 Scala 数组 val A = Array("please", "help", "me")。如何从这个数组中随机选择一个元素?
【问题讨论】:
例如,有一个 Scala 数组 val A = Array("please", "help", "me")。如何从这个数组中随机选择一个元素?
【问题讨论】:
import java.util.Random
// ...
val rand = new Random(System.currentTimeMillis())
val random_index = rand.nextInt(A.length)
val result = A(random_index)
【讨论】:
A.length 等于零,这将崩溃。永远不要忘记边缘情况
import scala.util.Random
val A = Array("please", "help", "me")
Random.shuffle(A.toList).head
【讨论】:
headOption,因为Seq(这里是Array)可能是空的。
import scala.util.Random
val A = List(1, 2, 3, 4, 5, 6)
A(Random.nextInt(A.size))
【讨论】:
A.size 等于零,这将崩溃。永远不要忘记边缘情况
A.lift(Random.nextInt(A.size)),它会给你Option[Int]
A.size 为 0 时崩溃
完全不涉及重新洗牌的更好答案是:
import scala.util.Random
object sample {
//gets random element from array
def arr[T](items:Array[T]):T = {
items(Random.nextInt(items.length))
}
}
这也通用
【讨论】:
我们还可以使用Option monad(使用lift 方法)添加一些安全性
实际上,在任何集合上使用此方法时, 即使您的集合为空,或者您的随机索引超出边界,您的结果也将始终是一个选项。
def getRandElemO[T](arr: Array[T]): Option[T] =
if (arr.isEmpty) None
else arr.lift(util.Random.nextInt(arr.length))
// or the one liner:
// def getRandElemO[T](arr: Array[T]): Option[T] =
// arr.headOption.flatMap(_ => arr.lift(util.Random.nextInt(arr.length)))
【讨论】:
如果您想要更惯用的解决方案,请考虑使用 typeclass 模式(scala 中的隐式类)。
implicit class ListOps[A](list: List[A]) {
def getRandomElement: Option[A] = list match {
case Nil => None
case _ => list.lift(scala.util.Random.nextInt(list.size))
}
def randomChoice(n: Int): Option[List[A]] =
(1 to n).toList.foldLeft(Option(List[A]()))((acc, e) => getRandomElement.flatMap(r => acc.map(a => a :+ r)))
}
现在,如果隐式类在范围内,您可以:
val randomElement: Option[String] = List("this", "is", "a", "list").getRandomElement
如果您确定该选项包含某个值,则可以使用get 方法。
randomElement.get // This will return a String (or a NotSuchElementExeption)
尽管如此,还是建议使用模式匹配或getOrElse:
randomElement match {
case None => ??? // This is what you do when a None is encounter (e.g. for empty lists)
case Some(result) => ??? // The variable result contains a string.
注意randomChoice 方法假定替换元素。
【讨论】: