質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

2831閲覧

Swiftで.random(in: 1...50)から抽出された値を(in: 1...50)から削除する方法

tutumikan64

総合スコア9

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/05/29 08:56

現在重複しないランダムな値を表示する機能を実装しているのですが、抽出後に重複チェックするのではなく抽出した値をその場でランダムの選択肢から削除する方法を探しております。
検索しても見つからなかったので、何か良い方法を知っていたら教えてください。

Swift

1randomNum = Int.random(in: 1...50)

1が出たら(in: 2...50)になるようなイメージです。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

出た数の状態を管理しないといけないため、配列変数を使うのが良いかと思います。いくつか方法があると思いますけれど、たとえば構造体を使って作ってみるのはいかがでしょう。

swift

1struct Random { 2 3 /// 乱数のリストを配列のインスタンスで管理します。 4 private(set) var numbers: Array<Int> 5 6 /// 値の列を使ってインスタンスを生成します。 7 /// - Parameter numbers: 乱数リストです。 8 init<S>(numbers: S) where S: Sequence, S.Element == Int { 9 10 self.numbers = Array(numbers) 11 } 12 13 /// 乱数用の配列から、ランダムで1つ取得します。 14 /// - Returns: ランダムで値をひとつ返します。値が出尽くしたときは `nil` を返します。 15 mutating func number() -> Int? { 16 17 // 乱数配列のインデックスをランダムで抽出します。 18 guard let index = numbers.indices.randomElement() else { 19 20 // 乱数配列が空だった場合は `nil` を返します。 21 return nil 22 } 23 24 // 全ての処理が終わった後で、乱数配列から今回使ったインデックスの値を削除するように処理を予約します。 25 defer { 26 numbers.remove(at: index) 27 } 28 29 // ランダムでピックアップしたインデックスが指す値を返します。 30 return numbers[index] 31 } 32}

このような構造体を作ると、次のようにして重複しない乱数を得ることができました。

swift

1 2var random = Random(numbers: 1 ... 50) 3 4while let number = random.number() { 5 6 print("乱数:", number, ", 残り:", random.numbers) 7}

投稿2020/05/29 09:18

編集2020/05/29 09:19
TomohiroKumagai

総合スコア441

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TomohiroKumagai

2020/05/29 10:24

TsukubaDepot さんのご回答を取り入れてコードを回収してみたら、思った想像以上に明解に記述できました。こちらでも良いかもしれません。 ```swift struct Random { /// 乱数のリストを配列のインスタンスで管理します。 private(set) var numbers: Array<Int> /// 値の列を使ってインスタンスを生成します。 /// - Parameter numbers: 乱数リストです。 init<S>(numbers: S) where S: Sequence, S.Element == Int { self.numbers = numbers.shuffled() } /// 乱数用の配列から、ランダムで1つ取得します。 /// - Returns: ランダムで値をひとつ返します。値が出尽くしたときは `nil` を返します。 mutating func number() -> Int? { // 乱数配列のインデックスをランダムで抽出します。 return numbers.popLast() } } ```
tutumikan64

2020/06/01 02:18

回答頂きありがとうございました、今回のアドバイスでとても勉強になりました!
guest

0

おそらくもう一つの方法です。

1...50で初期化された配列を用意し、要素をシャッフルしたあと、頭から順番に値を取り出しています。

ただし、この方法だと配列の残り数をご自身で管理する必要があるため、使い回しや安全性を考えるとTomohiroKumagaiが提案された構造体を作る方法の方がいいかと思います。

Swift

1import UIKit 2 3var num = [Int](1...50) 4print("最初の値: ", num) 5 6// 要素をシャッフルする 7num.shuffle() 8print("シャッフル後: ", num) 9 10repeat { 11 // 配列の最初の要素だけ取り出し、配列から削除 12 let dropped = num.removeFirst() 13 print("(dropped)", terminator: ", ") 14} while num.count > 0 15 16//最初の値: [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, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50] 17//シャッフル後: [36, 14, 48, 22, 33, 38, 18, 6, 13, 25, 8, 16, 21, 44, 40, 34, 49, 45, 17, 37, 47, 31, 50, 39, 4, 30, 35, 3, 7, 20, 10, 43, 23, 26, 28, 24, 15, 42, 12, 41, 5, 29, 2, 19, 9, 11, 32, 1, 46, 27] 18//36, 14, 48, 22, 33, 38, 18, 6, 13, 25, 8, 16, 21, 44, 40, 34, 49, 45, 17, 37, 47, 31, 50, 39, 4, 30, 35, 3, 7, 20, 10, 43, 23, 26, 28, 24, 15, 42, 12, 41, 5, 29, 2, 19, 9, 11, 32, 1, 46, 27,

投稿2020/05/29 10:05

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TomohiroKumagai

2020/05/29 10:19

`shuffle` すごく良いですね。配列には削除と取得を同時に行える `popLast` というメソッドもあるので、これらを使うと自分が提示したコードがもっと明解になりそうです。こちらのコードも、もしかすると数を管理しなくてもよくなるかもしれません。
TsukubaDepot

2020/05/29 10:23

なるほど、それは勉強になりました。 popLast()だと取り出せる要素がなくなれば nil が戻るので使いやすそうですね。
tutumikan64

2020/06/01 02:19

回答頂きありがとうございます。 Swift初心者なので勉強になりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問