- 更新日: 2015年12月14日
- Swift & iOS
SwiftでArray(配列)などをシャッフル
Swift 2 の環境で Array(配列)をランダムにシャッフルしたい機会があった。標準の API にはなかったようなので、検索してアルゴリズムを調べつつシャッフルメソッドを実装しました。
— 環境 —
Xcode 7.0
Swift 2.0
Mac OS X Yosemite 10.10.5
実装は以下のような感じ。
配列 Array や Range などをシャッフルするメソッド実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import UIKit // 破壊的に配列をシャッフルするメソッド func shuffleBang<T>(inout array: [T]) { for index in 0..<array.count { let newIndex = Int(arc4random_uniform(UInt32(array.count - index))) + index if index != newIndex { swap(&array[index], &array[newIndex]) } } } // 破壊的でないシャッフル / Array(配列)のみ引数で渡せる func shuffleArray<S>(source: [S]) -> [S] { var copy = source shuffleBang(©) return copy } // 破壊的でないシャッフル / Array(配列), Range などを引数で渡せる func shuffle<S: SequenceType>(source: S) -> [S.Generator.Element] { var copy = Array<S.Generator.Element>(source) shuffleBang(©) return copy } |
shuffleBang() は破壊的に配列をシャッフルするメソッドです。破壊的というのは、引数で渡した元の配列自体をシャッフルしてしまうという意味で使ってます、Ruby 的な用語かもしれません。
shuffleArray() は破壊的でないシャッフルメソッドで、引数には Array(配列)のみを受け付ける。shuffule() は破壊的でないシャッフルメソッドで、引数には Array, Range などを受け付ける。
実装のアルゴリズムは以下のページなどを参考にしました。
swift2 – fatal error: swapping a location with itself is not supported with Swift 2.0 – Stack Overflow
swiftでシャッフル関数 – Qiita
1 |
if index != newIndex { |
の行を書いているのは、Swift 2 だと以下のように同じインデックス位置の swap ができない、とエラーが発生するため。
1 2 3 |
swapping a location with itself is not supported |
Ruby の Array#shuffle 実装を参考にしてみた
Ruby の Array#shuffule の実装が気になったのでソースコードを読んでみたところ…
Ruby の Array#shuffule 実装 – GitHub
Ruby での実装の書き方のほうが分かりやすかったので、後ほどそれを真似た書き方に変更しました。
1 2 3 4 5 6 7 8 9 10 |
func shuffleBang<T>(inout array: [T]) { var index = array.count while index > 1 { let newIndex = Int(arc4random_uniform(UInt32(index))) index-- if index != newIndex { swap(&array[index], &array[newIndex]) } } } |
for でも while でもやってることは同じようなことかと思います。
Playground でのテスト
以下 Xcode の Playground での実験。
1 2 3 4 5 6 7 8 9 10 11 |
var arr = [1, 2, 3, 4, 5] // => [1, 2, 3, 4, 5] shuffleArray(arr) // => [2, 4, 5, 3, 1] arr // => [1, 2, 3, 4, 5] shuffleArray(1...5) // => error shuffle(arr) // => [5, 3, 1, 2, 4] arr // => [1, 2, 3, 4, 5] shuffle(1...5) // => [2, 5, 3, 1, 4] shuffleBang(&arr) // => [4, 2, 1, 3, 5] arr // => [4, 2, 1, 3, 5] |
目的通りに動作しているのを確認できた。
- Swift & iOS の関連記事
- WKWebView/UIWebViewでウェブページが真っ白
- Unityのインストールと初期設定
- WKWebView/UIWebViewでNavigation Barの下にウェブページが隠れるのを回避
- Navigation Controllerで画面遷移させるSwiftコード
- Swiftでタップ/スワイプのイベント処理実装・UITapGestureRecognizerとUISwipeGestureRecognizer
- UIPageViewController画面下部のUIPageControlを非表示にする
- Swiftのバージョン確認・REPL実行
- Xcode7.0アップデートで遭遇した課題2つ
- 正規のXcodeかどうかチェック(XcodeGhostマルウェア騒動)
- WKWebViewでtarget=”_blank”のリンクを開く(Swift)
Leave Your Message!