Как получить случайный элемент из набора в Scala
Для любого заданного набора, например,
val fruits = Set("apple", "grape", "pear", "banana")
как получить случайный элемент из fruits
?
Большое спасибо.
Ответы
Ответ 1
преобразовать в 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 = [email protected]
scala> fruits.toVector(rnd.nextInt(fruits.size))
res8: String = apple
Ответ 2
Итак, каждый отправленный ответ имеет сложность O (n) в терминах пространства,, поскольку они каким-то образом создают копию всей коллекции. Вот решение без какого-либо дополнительного копирования (следовательно, это "постоянное пространство" ):
def random[T](s: Set[T]): T = {
val n = util.Random.nextInt(s.size)
s.iterator.drop(n).next
}
Ответ 3
Solution1
Случайный способ (import scala.util.Random
)
scala> fruits.toList(Random.nextInt(fruits.size))
res0: java.lang.String = banana
Solution2
Математический способ (без импорта)
scala> fruits.toList((math.random*fruits.size).toInt)
res1: String = banana
Ответ 4
Вы можете напрямую получить доступ к элементу Set с срезом. Я использовал это, когда я работал с набором, который менялся в размере, поэтому преобразование его в вектор каждый раз казалось излишним.
val roll = new Random ()
val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
Ответ 5
import Scala.util.Random
val fruits = Set("apple", "grape", "pear", "banana").toVector
val sz =fruits.size
val num = Random.nextInt(sz)
fruits(num)
Ответ 6
Черпая вдохновение из других ответов на этот вопрос, я придумал:
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
вместо этого.
Ответ 7
Не преобразовывая 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
Ответ 8
Если вы не против решения O(n)
:
import util.Random
// val fruits = Set("apple", "grape", "pear", "banana")
Random.shuffle(fruits).head
// "pear"