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

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

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

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

2回答

2273閲覧

クイズのシャッフル出題について

xinxin

総合スコア16

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

1クリップ

投稿2018/12/25 14:45

前提・実現したいこと

swiftの初心者です。
今Xcodeで3択のクイズアプリを作成しています。
クイズ問題と3択の選択肢が出題され、回答した後に次の問題に移ります。
元々のコードではCSVデータを順に読み込むようになっており、","で分割され、改行ごとに1行分のデータになっていて、

クイズ問題,選択肢1,選択肢2,選択肢3,正解の選択肢番号

の順に記載されています。csvデータ内にデータは4つ入っています。今、CSVデータに記述されている問題をシャッフルして3問出題するにはどのようなコードを書けばいいのでしょうか。
ご教授お願いします。

発生している問題・エラーメッセージ

シャッフルをするのにrandomToolを使ったのですが、試しに実行をしても全然シャッフルされていなく、csvデータの順番に出題されています。

該当のソースコード

swift

1import Foundation 2 3class QuestionData { 4 var question: String 5 var answer1: String 6 var answer2: String 7 var answer3: String 8 var correctAnswerNumber: Int 9 var userChoiceAnswerNumber: Int? 10 11 // 問題文の番号 12 var questionNo: Int = 0 13 14 // クラスが生成された時の処理 15 init(questionSourceDataArray: [String]) { 16 question = questionSourceDataArray[0] 17 answer1 = questionSourceDataArray[1] 18 answer2 = questionSourceDataArray[2] 19 answer3 = questionSourceDataArray[3] 20 correctAnswerNumber = Int(questionSourceDataArray[4])! 21 } 22 23 // ユーザが選択した答えが正解かどうか判定する 24 func isCorrect() -> Bool { 25 // 答えが一致しているかどうか判定する 26 if correctAnswerNumber == userChoiceAnswerNumber { 27 // 正解 28 return true 29 } 30 // 不正解 31 return false 32 } 33} 34 35// クイズデータ全般の管理と生成を管理するクラス 36class QuestionDataManager { 37 38 // シングルトンのオブジェクトを生成 39 static let sharedInstance = QuestionDataManager() 40 41 // 問題を格納するための配列 42 var questionDataArray = [QuestionData]() 43 44 // 現在の問題のインデックス 45 var nowQuestionIndex = 0 46 47 // 初期化処理 48 private init() { 49 // シングルトンであることを保証するためにprivateで宣言しておく 50 } 51 //問題数のカウント 52 var counter = 0 53 54 // 問題文の読み込み処理 55 func loadQuestion() { 56 // 格納済みの問題文であればいったん削除しておく 57 questionDataArray.removeAll() 58 // 現在の問題のインデックスを初期化 59 nowQuestionIndex = 0 60 61 // csvファイルパスを取得 62 guard let csvFilePath = Bundle.main.path(forResource: "question", ofType: "csv") else { 63 // csvファイルなし 64 print("csvファイルが存在しません") 65 return 66 } 67 68 do { 69 let csvStringData = try String(contentsOfFile: csvFilePath, encoding: String.Encoding.utf8) 70 // csvデータを1行ずつ読み込む 71 csvStringData.enumerateLines ( invoking: {(line, stop) -> () in 72 // カンマ区切りで分割 73 let questionSourceDataArray = line.components(separatedBy: ",") 74 // 問題データを格納するオブジェクトを作成 75 let questionData = QuestionData(questionSourceDataArray: questionSourceDataArray) 76 // 問題を追加 77 self.questionDataArray.append(questionData) 78 // 問題番号を設定 79 questionData.questionNo = self.questionDataArray.count 80 }) 81 } catch let error { 82 print("csvファイル読み込みエラーが発生しました(error)") 83 return 84 } 85 } 86 //配列に同じ数値を入れて初期化 87 var questionArrayCut = [Int](repeating: 0 , count: 3) 88 func randomTool() { 89 //0~3の中から重複しない4個の乱数を生成し、配列に入れてもどす 90 let questionArray: [Int] = [0, 1, 2, 3] 91 var questionArray_Shuffled = questionArray.shuffled() 92 93 for n in 0...2 { 94 questionArrayCut[n] = questionArray_Shuffled[n+5] 95 print(questionArrayCut[n]) 96 } 97 } 98 // 次の問題を取り出す 99 func nextQuestion() -> QuestionData? { 100 if counter < 3 { 101 //ここでランダム 102 //counterが0~2の範囲で1ずつ増えるため、配列の値を取得 103 let qArray: [Int] = questionArrayCut 104 nowQuestionIndex = qArray[counter] 105 print(nowQuestionIndex) 106 let nextQuestion = questionDataArray[counter] 107 counter += 1 108 return nextQuestion 109 }else{ 110 counter = 0 111 } 112 return nil 113 } 114 115} 116 117

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

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

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

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

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

guest

回答2

0

答えをランダムに表示したいってことですよね?
私ならこんな感じにやります

Swift

1var question: String = "質問だよ" 2var answer1: String = "答え1" 3var answer2: String = "答え2" 4var answer3: String = "答え3" 5 6var ansArr:[String] = [answer1, answer2, answer3] 7 8for i in 0..<ansArr.count { 9 //print(ansArr[Int(arc4random()) % ansArr.count]) 10 let randomElementCount = Int(arc4random()) % ansArr.count 11 12 let element = ansArr[randomElementCount] 13 print(element) 14 ansArr.remove(at: randomElementCount) 15}

playgroundで実行してみるとこんな感じにランダムできていることがわかると思います。

console

1答え3 2答え1 3答え2

投稿2018/12/26 10:13

harumi

総合スコア407

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

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

xinxin

2018/12/29 09:05

ありがとうございます。ちなみに質問などが全部csvデータにある場合でもこういうのを使うんでしょうか?このコードを見たところ一問一問コードを書かないといけないように見えるのですが。あと、このコードを入れるのは最初の方のinit()の前でいいんでしょうか? 初心者で何もわからなくてすみません。ご教授お願いします。
guest

0

ややこしく考えすぎです。

以下は、3問だけ出題する場合。

func loadQuestion()catchの前に

swift

1 do { 2 let csvStringData = try String(contentsOfFile: csvFilePath, encoding: String.Encoding.utf8) 3 // csvデータを1行ずつ読み込む 4 csvStringData.enumerateLines ( invoking: {(line, stop) -> () in 5 // カンマ区切りで分割 6 let questionSourceDataArray = line.components(separatedBy: ",") 7 // 問題データを格納するオブジェクトを作成 8 let questionData = QuestionData(questionSourceDataArray: questionSourceDataArray) 9 // 問題を追加 10 self.questionDataArray.append(questionData) 11 // 問題番号を設定 12 questionData.questionNo = self.questionDataArray.count 13 }) 14 15 // シャッフルして最初の3つを取り出す。 16 questionDataArray = Array(questionDataArray.shuffled().prefix(3)) 17 } catch let error { 18 ... 19

でいいです。

すでにquestionDataArrayがシャッフルされて3問だけになっているので、

swift

1func nextQuestion() -> QuestionData? { 2 3 return questionDataArray.popLast() 4}

でいいです。

投稿2018/12/25 15:27

編集2018/12/26 12:17
MasakiHori

総合スコア3384

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

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

xinxin

2018/12/26 04:53

var questionArrayCut = [Int](repeating: 0 , count: 3) から後ろを func nextQuestion() -> QuestionData? { return questionArray.popLast() } に変えるっていうことですか?そうしたら questionArray = Array(questionArray.shuffled().prefix(3)) を挿入したところは”Expected declaration”と出ました。 また、questionArray のところは全てエラーが出ました。questionDataArrayではないかと言われました。
MasakiHori

2018/12/26 07:59

questionArray のところはすべてquestionDataArrayですね。
xinxin

2018/12/26 08:43

実行をしたらcsvデータの4、3、2、1の順にクイズが4問出て来ました。シャッフルになっていなく、しかも4問出て来ました。
MasakiHori

2018/12/26 09:51

私の提示してる// シャッフルして最初の3つを取り出す。 とコメント書いた部分の挿入位置が間違っていませんか? catchの「前」の行です
xinxin

2018/12/29 06:22

なるほど!しかし、問題は3問のシャッフルになりましたけど問題番号がcvsデータの順になってしまいました。また、問題に正解してるのにその後の画面では0問の正解になってしまいました。
MasakiHori

2018/12/31 00:11

QuestionDataのquestionNoが問題の通し番号でないのならQuestionDataに持たせるのは設計上良くないです。 問題出題にかかわるクラスが現在何問目かを記録するようにすると良いでしょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問