web-dev-qa-db-ja.com

Scalaのセットからランダムな要素を取得する方法

たとえば、任意のセットについて、

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

fruitsからランダムな要素を取得する方法

どうもありがとう。

21
elm

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 = scala.util.Random@31a9253

scala> fruits.toVector(rnd.nextInt(fruits.size))
res8: String = Apple
20
Govind Singh

したがって、以前に投稿されたすべての回答は、スペースの観点から複雑O(n)です。これは、何らかの方法でコレクション全体のコピーを作成するためです。以下は、追加のコピーを行わないソリューションです(したがって、「一定のスペース」です)。

def random[T](s: Set[T]): T = {
  val n = util.Random.nextInt(s.size)
  s.iterator.drop(n).next
}
20
Rok Kralj

スライスを持つセットの要素に直接アクセスできます。サイズが変化するセットで作業しているときにこれを使用したため、毎回ベクターに変換するのはやり過ぎのようでした。

val roll = new Random ()

val n = roll nextInt (fruits size)
fruits slice (n, n + 1) last
2
Wayne

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

この質問に対する他の回答からインスピレーションを得て、私は次のことを思いつきました。

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を返すことができます。

   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

O(n)ソリューションを気にしない場合:

import util.Random

// val fruits = Set("Apple", "grape", "pear", "banana")
Random.shuffle(fruits).head
// "pear"
0
Xavier Guihot

Setorderedコレクションに変換するのではなく、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
_
0
elm