Pour un ensemble donné, par exemple,
val fruits = Set("Apple", "grape", "pear", "banana")
comment obtenir un élément aléatoire de fruits
?
Merci beaucoup.
convertir en Vector
et en tirer un élément aléatoire
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
Ainsi, chaque réponse postée auparavant a une complexité O(n) en termes d'espace, puisqu'elle crée une copie de toute une collection. Voici une solution sans aucune copie supplémentaire (il s’agit donc d’un "espace constant"):
def random[T](s: Set[T]): T = {
val n = util.Random.nextInt(s.size)
s.iterator.drop(n).next
}
Vous pouvez accéder directement à un élément d'un ensemble avec tranche. Je l’utilisais lorsque je travaillais avec un ensemble dont la taille changeait. Il était donc excessif de le convertir en vecteur.
val roll = new Random ()
val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
Solution1
Manière aléatoire (import scala.util.Random
)
scala> fruits.toList(Random.nextInt(fruits.size))
res0: Java.lang.String = banana
Solution2
Manière mathématique (pas d'importations)
scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana
S'inspirant des autres réponses à cette question, j'ai proposé:
private def randomItem[T](items: Traversable[T]): Option[T] = {
val i = Random.nextInt(items.size)
items.view(i, i + 1).headOption
}
Cela ne copie rien, n'échoue pas si la Set
(ou un autre type de Traversable
) est vide, et on voit clairement ce que cela fait. Si vous êtes certain que la variable Set
n'est pas vide, vous pouvez remplacer .head
et renvoyer T
à la place.
import Scala.util.Random
val fruits = Set("Apple", "grape", "pear", "banana").toVector
val sz =fruits.size
val num = Random.nextInt(sz)
fruits(num)
En ne convertissant pas la Set
en une collection ordonnée mais en utilisant zipWithIndex
, nous pouvons attribuer un index à chaque élément de la collection,
fruits.zipWithIndex
Set((Apple,0), (grape,1), (pear,2), (banana,3))
Donc pour val rnd = util.Random.nextInt(fruits.size)
,
fruits.zipWithIndex.find( _._2 == rnd)
Option[(String, Int)] = Some((banana,3))
Étant donné un ensemble vide,
Set[String]().zipWithIndex.find( _._2 == 3)
Option[(String, Int)] = None