2015-03-13 35 views
2

以下是从1到45范围内的号码乐透模拟的必要解决方案,每当我们产生一个数字n1时,号码从可能的集合中移除数字。斯卡拉:模拟乐透号码发生器范围1至45

是否有可能以更实用的方式实现相同?即使用图,过滤器等

def getNumbers :Array[Int] = { 

     val range = 1 to 45 
     var set = range.toSet 

     var resultSet:Set[Int] = Set() 
     var current: Int = 0 

     while(resultSet.size < 5){ 
      current = Random.shuffle(set).head // pick the head of the shuffled set 
      set -= current 
      resultSet += current 
     } 

     resultSet.toArray 
    } 

“编辑”

一个例子挑3号从范围1到5

Original Set is {1,2,3,4,5} 
{1,2,3,4,5} shuffle(1) picked at random 3 
{1,2,4,5}  shuffle(2) picked at random 2 
{1,4,5}  shuffle(3) picked at random 4 
original Set becomes {1,5} 

numbers picked {3,2,4} 

各洗牌随机化一组不同的! =>不同的概率

我希望看到一个功能性的“方法”,5个洗牌不是1洗牌!

+2

对不起,但不同的排序影响不成立的可能性的假设。功能解决方案与您在统计基本书中所描述的一样。您的额外限制或模拟将模拟绘图的行为,但不足以形成真正的功能解决方案。 – 2015-03-13 22:16:15

+0

不是订单,大小不一样,每次洗牌后减少一次 – firephil 2015-03-13 22:21:47

回答

0

这将模拟你想要的行为:

画一个,左洗牌的数据,得出一个等等。

import scala.util.Random 
import scala.annotation.tailrec 

def draw(count: Int, data: Set[Int]): Set[Int] = { 

    @tailrec 
    def drawRec(accum: Set[Int]) : Set[Int] = 
    if (accum.size == count) 
     accum 
    else 
     drawRec(accum + Random.shuffle((data -- accum).toList).head) 

    drawRec(Set())  
} 

scala> draw(5, (1 to 45).toSet) 
res15: Set[Int] = Set(1, 41, 45, 17, 22) 

scala> draw(5, (1 to 45).toSet) 
res16: Set[Int] = Set(5, 24, 1, 6, 28) 
7

当然,这是可能的。集合API包含您需要的一切。你要找的是take,它将采集该集合中的第一个n元素,或者如果该集合的元素少于n,则会采用该元素中的第一个元素。

Random.shuffle(1 to 45).take(5).toArray 
+0

每次我需要减少前一个数字的设置,所以这个简单的解决方案是不正确的100% – firephil 2015-03-13 19:29:47

+3

@firephil你是什么意思?该集合不包含重复项,因此不可能两次选择相同的元素。 – 2015-03-13 19:31:04

+0

虽然可能性不尽相同,但想象一下真正的彩票,当你生成一个数字时,这个数字将从可能的数字集合中取出(1个洗牌对5个足球) – firephil 2015-03-13 19:38:44

1

我与这个MZ,但是如果你真的想要一个不断洗牌的功能形式,那么你想是这样的:

import scala.util.Random 
import scala.annotation.tailrec 

val initialSet = 1 to 45 

def lottery(initialSet: Seq[Int], numbersPicked: Int): Set[Int] = { 
    @tailrec 
    def internalTailRec(setToUse: Seq[Int], picksLeft: Int, selection: Set[Int]):Set[Int]= { 
    if(picksLeft == 0) selection 
    else { 
     val selected = Random.shuffle(setToUse).head 
     internalTailRec(setToUse.filter(_ != selected), picksLeft - 1, selection ++ Set(selected)) 
    } 
    } 
    internalTailRec(initialSet, numbersPicked, Set()) 
} 

lottery(initialSet, 5) 
+0

是的,这就是我的意思,我正在考虑使用辅助函数的内部函数递归,但我想知道是否存在一个更简单的解决方案 - 技巧... – firephil 2015-03-13 21:36:02

0

我喜欢@ MZ的解决方案,以及并同意他关于概率的推理。阅读Random.shuffle的来源可能是一项值得的练习。

每次迭代都会从range中删除一个元素,并将其添加到累加器acc,这与您的命令式方法类似,不同之处在于我们不会更改集合和计数器。

import scala.util.Random._ 
import scala.annotation.tailrec 

def getNumbers(): Array[Int] = { 
    val range = (1 to 45).toSeq 
    @tailrec 
    def getNumbersR(range: Seq[Int], acc: Array[Int], i: Int): Array[Int] = (i, range(nextInt(range.size))) match{ 
    case (i, x) if i < 5 => getNumbersR(range.filter(_ != x), x +: acc, i + 1) 
    case (i, x)   => acc 
    } 
    getNumbersR(range, Array[Int](), 0) 
} 

scala> getNumbers 
res78: Array[Int] = Array(4, 36, 41, 20, 14) 
+0

有趣的方法,与模式匹配和递归 – firephil 2015-03-13 22:19:36