Swift 4.2 更方便的亂數 function,random,randomElement & shuffle

Swift 4.2 SE-0202 的 Random Unification 讓我們在開發 iOS App 時,亂數功能變得更容易了。現在我們不再需要額外加入 GameplayKit,也不用使用轉型很麻煩的 function arc4random_uniform。而且更棒的是,現在甚至可以直接用 array 亂數,隨機取出裡面的成員,或是像洗牌一樣將 array 隨機排序也不是問題。到底新的亂數功能有多方便呢 ? 就讓我們一探究竟吧。

1 整數的亂數

呼叫 Int 的 function random(in:) 生成 Int 型別的亂數,在參數裡傳入數字的範圍。

var number = Int.random(in: 0...2)

傳入 ..< 的範圍也不是問題。

var number = Int.random(in: 1..<10)

傳入包含負數的範圍也可以。

var number = Int.random(in: -5...5)

2 浮點數的亂數

呼叫 Double 的 function random(in:) 生成 Double 型別的亂數,在參數裡傳入數字的範圍。

var number = Double.random(in: 1.5...3.2)

想生成 Float 型別的亂數也可以。

var number = Float.random(in: 1.5...3.2)

3 CGFloat 的亂數

開發 iOS App 時,時常會遇到 CGFloat 型別的參數。比方以下例子,當我們用 Float 亂數紅色的數值,生成 UIColor 物件時,將產生問題。

import UIKit

var red = Float.random(in: 0...1)
var color = UIColor(red: red, green: 0, blue: 0, alpha: 1)

因為 red 參數的型別是 CGFloat,不能傳入 Float。

此時我們可將 Float 型別的 red 生成 CGFloat 解決問題,但其實有更聰明的做法。

var color = UIColor(red: CGFloat(red), green: 0, blue: 0, alpha: 1)

我們可以一開始就用 CGFloat 生成亂數。

import UIKit

var red = CGFloat.random(in: 0...1)
var color = UIColor(red: red, green: 0, blue: 0, alpha: 1)

4 Bool 的亂數

呼叫 Bool 的 function random() 生成 Bool 型別的亂數,答案很簡單,只有兩種可能,true 或 false,就好像告白一樣,只有成功和失敗兩種結果。

let isCute = Bool.random()

Bool 的亂數很適合做像丟銅板,博杯之類的應用。

5 array 的亂數

從前為了亂數 array 裡的某個成員,我們往往先從 0 ~ array 成員數量 -1 裡亂數一個數字,然後再從 array 裡取出此編號的成員,比方以下從永遠的四大天王亂數取出其中一個偶像的例子:

let 四大天王 = ["劉德華", "張學友", "郭富城", "彼得潘"]
let number = Int.random(in: 0...四大天王.count-1)
let idol = 四大天王[number]

現在不用這麼麻煩了,array 就可以直接亂數,只要呼叫它的 function randomElement()。

let 四大天王 = ["劉德華", "張學友", "郭富城", "彼得潘"]
let idol = 四大天王.randomElement()

不過有一點要特別注意,randomElement 回傳的東西是 optional,因此剛剛例子裡的 idol 型別將是 String?。

只有當 array 是空的時候才會回傳 nil,因此當 array 有內容時,我們可以放心加上 ! 取值。

let teams = ["統一7-ELEVEn獅", "中信兄弟", "富邦悍將", "樂天桃猿"]
let team = teams.randomElement()!

6 集合型別的亂數

剛剛的 function randomElement() 其實不是 array 獨享。像是 range,dictionary,set 等都可以呼叫,亂數取出其中的成員,而且一樣的,回傳的型別也是 optional。

let numbers = 1...10
let number = numbers.randomElement()
let cityDic = ["英國": "倫敦", "法國": "巴黎"]
let city = cityDic.randomElement()
let heroes = Set(["彼得潘", "彼得兔", "彼得帕克"])
let name = heroes.randomElement()

7 平均分配的亂數

某些時候我們會想要平均分配的亂數,確保不會亂數到一樣的東西,比方像選擇題或撲克牌之類的 App,連續亂數到兩張黑桃 A 可就變成出老千了。

Swift 特別提供 shuffle function 幫我們解決這個問題。shuffle 是什麼意思呢 ? 想當年彼得潘去拉斯維加斯玩慈善撲克牌大賽時,學到了 shuffle 是洗牌的意思。因此你可以將 shuffle 想成它會將 52 張撲克牌隨機排序,讓玩家每次玩都拿到不同的牌,而且不會拿到重覆的牌。

iPod shuffle 也能幫助我們理解 shuffle 的意思。iPod shuffle 完全沒有螢幕,所以我們無法找歌。那我們要怎麼聽音樂呢 ? 很簡單,它會亂數播放。

function shuffle 可幫我們將集合裡的成員隨機排序,比方我們可用此方法將程式裡存放撲克牌的 array 排序,讓每次玩時拿到不同的牌,並且避免賭神再世,拿到兩張黑桃 A 的窘境。

接下來,我們就以存放著情歌的 array 為例,利用 shuffle 幫我們決定播放的順序。

var songs = ["你好不好", "小幸運", "連名帶姓"]
songs.shuffle()

如上圖所示,shuffle 會將 array 重新排序,所以到時候第一首播小幸運,第二首播你好不好,第三頁播連名帶姓。

function shuffle 沒有回傳東西,它會改變原本的集合,因此剛剛例子的array songs 將被改變。

但還有另一個很類似的 function 叫 shuffled。

var songs = ["你好不好", "小幸運", "連名帶姓"]
let newSongs = songs.shuffled()
songs
newSongs

在 Swift 裡一般以英文 ed 結尾的 function 都有個特性。它們不會改變原本的東西,而是將新的東西回傳。因此 function shuffled 不會改變原本的集合,而是將隨機排序的集合回傳。在剛剛的例子,新排序的歌單將存在 newSongs,songs 是不受影響的。

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com