Für eine bestimmte Menge, zum Beispiel,
val fruits = Set("Apple", "grape", "pear", "banana")
wie bekomme ich ein zufälliges Element aus fruits
?
Danke vielmals.
konvertiere in Vector
und erhalte ein zufälliges Element daraus
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 = [email protected]
scala> fruits.toVector(rnd.nextInt(fruits.size))
res8: String = Apple
Jede Antwort, die zuvor gepostet wurde, ist also O(n) in Bezug auf den Platz komplex, da sie auf irgendeine Weise eine Kopie einer gesamten Sammlung erstellen. Hier ist eine Lösung ohne zusätzliches Kopieren (daher ist es "konstanter Raum"):
def random[T](s: Set[T]): T = {
val n = util.Random.nextInt(s.size)
s.iterator.drop(n).next
}
Sie können direkt auf ein Element eines Sets mit Slice zugreifen. Ich habe dies verwendet, als ich mit einem Set gearbeitet habe, dessen Größe sich geändert hat, sodass es mir jedes Mal wie ein Overkill vorkam, es in einen Vector umzuwandeln.
val roll = new Random ()
val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
Solution1
Zufälliger Weg (import scala.util.Random
)
scala> fruits.toList(Random.nextInt(fruits.size))
res0: Java.lang.String = banana
Solution2
Mathe Weg (keine Importe)
scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana
Ich habe mich von den anderen Antworten auf diese Frage inspirieren lassen und mir Folgendes ausgedacht:
private def randomItem[T](items: Traversable[T]): Option[T] = {
val i = Random.nextInt(items.size)
items.view(i, i + 1).headOption
}
Dies kopiert nichts, schlägt nicht fehl, wenn die Set
(oder eine andere Art von Traversable
) leer ist, und es ist auf einen Blick klar, was sie tut. Wenn Sie sicher sind, dass die Set
nicht leer ist, können Sie .head
ersetzen und stattdessen T
zurückgeben.
import Scala.util.Random
val fruits = Set("Apple", "grape", "pear", "banana").toVector
val sz =fruits.size
val num = Random.nextInt(sz)
fruits(num)
Wenn Ihnen eine O(n)
Lösung nichts ausmacht:
import util.Random
// val fruits = Set("Apple", "grape", "pear", "banana")
Random.shuffle(fruits).head
// "pear"
Wir konvertieren die Set
nicht in eine geordnete Sammlung, sondern verwenden zipWithIndex
, um jedem Element in der Sammlung einen Index zuzuweisen.
fruits.zipWithIndex
Set((Apple,0), (grape,1), (pear,2), (banana,3))
Also für val rnd = util.Random.nextInt(fruits.size)
,
fruits.zipWithIndex.find( _._2 == rnd)
Option[(String, Int)] = Some((banana,3))
Bei einer leeren Menge
Set[String]().zipWithIndex.find( _._2 == 3)
Option[(String, Int)] = None