2015-03-13 62 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