web-dev-qa-db-fra.com

Comment obtenir un élément aléatoire d'un Set in Scala

Pour un ensemble donné, par exemple,

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

comment obtenir un élément aléatoire de fruits?

Merci beaucoup.

16
elm

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
18
Govind Singh

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
}
17
Rok Kralj

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
2
Wayne

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
2
AmeyChavan

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.

1
   import Scala.util.Random

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

   val sz =fruits.size

   val num = Random.nextInt(sz)

   fruits(num)
1
Ashalynd

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
0
elm