测验应用程序从 8 组问题中随机选择问题?
Posted
技术标签:
【中文标题】测验应用程序从 8 组问题中随机选择问题?【英文标题】:Quiz app to pick questions from 8 group of questions randomly? 【发布时间】:2017-11-03 03:31:44 【问题描述】:我为 ios 构建了一个应用程序,我希望它从 8 个不同的问题组中随机选择问题。问题数量为 356,其中只有 50 个必须随机选择。
-
第一组的 8 个问题
第二组的 5 个问题
第三组的 5 个问题
来自第四组的 6 个问题
第 5 组的 6 个问题
来自第 6 组的 5 个问题
来自第 7 组的 9 个问题
第 8 组的 6 个问题
总共:50 个问题。
我所做的是,我构建了测验,但它会读取所有问题并将它们显示给用户。这些问题是从 .json 文件中读取的。
这是我的代码: (因为代码上没有cmets,问我吧。)
import UIKit
struct Question
var Question: String!
var Answers: [String]!
var Answer: Int!
init(item: [String: Any])
self.Question = item["Question"] as? String
self.Answers = item["Answers"] as? [String]
self.Answer = item["Answer"] as? Int
class LittleTestViewController: UIViewController
//MARK: Properties
@IBOutlet weak var questionLabel: UILabel!
@IBOutlet var buttons: [UIButton]!
var Questions = [Question]()
var QNumber = Int()
var answerNumber = Int()
override func viewDidLoad()
super.viewDidLoad()
jsonParsingQuestionsFile()
pickQuestion()
func jsonParsingQuestionsFile ()
guard let path = Bundle.main.path(forResource: "data", ofType: "json"),
let array = (try? JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe), options: JSONSerialization.ReadingOptions.allowFragments)) as? [[String : Any]] else
return
for item in array
self.Questions.append(Question(item: item))
func pickQuestion ()
if Questions.count > 0
QNumber = 0
questionLabel.text = Questions[QNumber].Question
answerNumber = Questions[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else
print ("End")
@IBAction func btn1(_ sender: UIButton)
Unhide()
if answerNumber == 0
print ("Correct!!")
else
@IBAction func btn2(_ sender: UIButton)
Unhide()
if answerNumber == 1
print ("Correct!!")
else
@IBAction func btn3(_ sender: UIButton)
Unhide()
if answerNumber == 2
print ("Correct!!")
else
@IBAction func btn4(_ sender: UIButton)
Unhide()
if answerNumber == 3
print ("Correct!!")
else
data.json
[ "Question":"Group 1. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 1. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 1. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 3,
"Question":"Group 2. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 2. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 1,
"Question":"Group 2. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 3. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 3. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 4. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 4. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 3,
"Question":"Group 4. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 5. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 0,
"Question":"Group 5. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 6. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 0,
"Question":"Group 7. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,
"Question":"Group 8. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 0,
"Question":"Group 8. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 1,
"Question":"Group 9. lalala?", "Answers":["lala","trtr","asas","bbbb"],"Answer": 2,]
这个 .json 文件只是一个示例,每个组都有更多问题。每个小组有大约 45 个问题。
【问题讨论】:
【参考方案1】:不要用代码弄乱你的逻辑。
如果您担心时间复杂性 - 难以实施,请按照此操作
只需按照以下算法即可。
由于您有 8 个组,因此创建一个整数数组,该数组最多可容纳 8 个值并使用全 0 进行初始化
Array(1) = [0 0 0 0 0 0 0 0]
并创建另一个数组,其中包含可以从看起来像的每个组中提取的最多问题
Array(2) = [8 5 5 6 6 5 9 6]
另外,应该有一个数组来保存每个组中剩余的问题数
n[] = [ 8elements ] not mensioned in question
开始
循环
1) 创建一个1-8之间的随机数来选择组
2) 检查小组是否已经选择了最多的问题。通过比较 array(1) 和 array(2) 数组,如果是,请再次执行第 1 步。
3) 让随机选择的组中的最大问题为 n。生成一个介于 1-n 之间的随机数。数组(1)中对应位置加1,n减1。从组中删除选中的问题 检查您是否达到 50 个问题 如果是,请退出 如果没有,请执行第 4 步
4) 将您随机选择的问题保存在某处。并继续执行第 1 步
最好将 50 个问题附加到一个数组中并放入 UI。
这是您不考虑复杂性的时候 - 易于实现
为此,您需要将所有问题组随机播放
Refer this post shuffle
然后从每个组中提取第一组问题(你想要多少)。这将是随机的。
给你的建议:先解决问题,再写代码!
【讨论】:
【参考方案2】:我建议您制作一个新的 .json 文件,其中包含 8 个不同组中的 8 组问题,例如问题 1、问题 2 等。然后使用开关制作 8 个案例,如果选择的问题数量则打破每个案例random 是您希望每个组的数字。
【讨论】:
【参考方案3】:感谢大家的建议。但我找到了如何做到这一点的方法。我只更改了 pickQuestion 函数。
func pickQuestion ()
if Questions.count > 0 && questionscount < 8
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("KEK").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("KEK")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions[QNumber].Answers[i], for: UIControlState.normal)
print(QNumber)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 13
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("M").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("M")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("M")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("M")[QNumber].Answers[i], for: UIControlState.normal)
print(QNumber)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 18
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("N").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("N")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("N")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("N")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 24
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("A").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("A")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("A")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("A")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 30
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("ΑΔ").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("ΑΔ")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("ΑΔ")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("ΑΔ")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 35
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("ΕΠ").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("ΕΠ")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("ΕΠ")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("ΕΠ")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 44
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("T").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("T")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("T")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("T")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else if Questions.count > 0 && questionscount < 50
QNumber = Int(arc4random_uniform(UInt32(Questions.filter$0.Question.hasPrefix("ΑΝΘ").count)))
questionscount += 1
questionLabel.text = Questions.filter$0.Question.hasPrefix("ΑΝΘ")[QNumber].Question
self.title = "Ερώτηση: \(Int(questionscount))/50"
answerNumber = Questions.filter$0.Question.hasPrefix("ΑΝΘ")[QNumber].Answer
for i in 0..<buttons.count
buttons[i].setTitle(Questions.filter$0.Question.hasPrefix("ΑΝΘ")[QNumber].Answers[i], for: UIControlState.normal)
Questions.remove(at: QNumber)
else
let alert = UIAlertController(title: "Σκόρ", message: "Απάντησες σωστά τις \(Int(score)) από τις \(Int(questionscount)) ερωτήσεις! \n \(String(format: "%.0f",(score/questionscount*100))) %", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Μενού", style: UIAlertActionStyle.default, handler: action in
self.navigationController?.popToRootViewController(animated: true)
))
self.present(alert, animated: true, completion: nil)
Hide()
【讨论】:
检查你做了什么,有一半的时间你只是改变了前缀。可能值得尝试创建另一个将前缀作为参数的函数。可读性和可维护性将迅速提高。【参考方案4】:根据您的data.json
,您将收到一个包含 356 个问题的列表。 “8 个组*”只是组名称,每个“问题”的一个“属性”就是组。
如果您实际上是在组个问题中接收数据,那么第一步是将它们一起附加到一个组中,如此处所示。
那么,如何从 356 个问题的列表中显示 50 个随机问题?
生成一个由 0 到 355 的数字组成的数组(数组从零开始)。 随机播放该数组。那里有很多很好的例子 - 这里有一个相当全面的参考:https://***.com/a/24029847/6257435数组的前 50 个元素现在包含 0 到 355 之间的随机(无重复)值,因此您可以简单地按该顺序显示实际问题。
编辑:
如果要求包括每组预定数量的问题,那只会增加几个步骤:
不要使用包含所有 356 个问题的大数组,而是将您的 json 数据拆分为 8 个数组,每个数组包含属于特定组的问题。
然后,将这些数组添加到“组”的二维数组中。
接下来,构建一个由问题“ID”编号组成的二维数组 - 只是每组中从 0 到问题数量的序列 - 然后随机排列每个数组。
结果将是每组的 X 个随机问题。
这是一个可以在 Playground 页面中运行的简单示例。该代码生成一个 Question 对象数组,以及相应的“索引”打乱数组。点击“下一个问题”按钮将逐步查看结果。
import UIKit
import PlaygroundSupport
// simple random number function
func random(_ range:Range<Int>) -> Int
return range.lowerBound + Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound)))
// shuffling extension
extension MutableCollection where Indices.Iterator.Element == Index
/// Shuffles the contents of this collection.
mutating func shuffle()
let c = count
guard c > 1 else return
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1))
let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else continue
let i = index(firstUnshuffled, offsetBy: d)
swap(&self[firstUnshuffled], &self[i])
extension Sequence
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Iterator.Element]
var result = Array(self)
result.shuffle()
return result
// Question object
struct Question
var Question: String!
var Answers: [String]!
var Answer: Int!
init(item: [String: Any])
self.Question = item["Question"] as? String
self.Answers = item["Answers"] as? [String]
self.Answer = item["Answer"] as? Int
// standard UIViewController
class TestViewController : UIViewController
// standard UIButton
let btn: UIButton =
let b = UIButton()
b.setTitle(" Next Question ", for: .normal)
b.backgroundColor = .red
b.translatesAutoresizingMaskIntoConstraints = false
return b
()
// standard UILabel
let questionLabel: UILabel =
let v = UILabel()
v.backgroundColor = .white
v.numberOfLines = 0
v.translatesAutoresizingMaskIntoConstraints = false
return v
()
// two-dimensional array of Question objects
var arrayOfQuestions = [[Question]]()
// two-dimension array of shuffled Index values
var arrayOfIDs = [[Int]]()
// number of questions per group
let questionsPerGroup = [8, 5, 5, 6, 6, 5, 9, 6]
// note: arrays are Zero-based,
// so "first question" index will be Zero
// and "first group" index will be Zero
// start Question counter at -1 so "next question" will be Zero
var currentQuestion: Int = -1
// group counter
var currentGroup: Int = 0
override func viewDidLoad()
super.viewDidLoad()
// this is just generating 8 groups of Questions that look like:
// "Question":"Group: 1 Question: 1", "Answers":["A", "B", "C", "D"], "Answer":1
for iGroup in 1...8
// each group will have between 43 and 48 questions
let numQuestions = random(43..<49)
// new empty array
var aGroup = [Question]()
for iQuestion in 1...numQuestions
let s: [String:Any] = [
"Question":"Group: \(iGroup) Question: \(iQuestion)",
"Answers":["A", "B", "C", "D"],
"Answer": random(0..<3)
]
let q = Question(item: s)
aGroup.append(q)
// append this "group" to the array
arrayOfQuestions.append(aGroup)
// create array of numbers 0 through number of questions -1
let aIDs = Array(0..<numQuestions)
// shuffle that array and append to "IDs" array
arrayOfIDs.append(aIDs.shuffled())
// add a button and label to the view
self.view.addSubview(btn)
self.view.addSubview(questionLabel)
btn.topAnchor.constraint(equalTo: view.topAnchor, constant: 40.0).isActive = true
btn.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0).isActive = true
questionLabel.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0).isActive = true
questionLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0).isActive = true
questionLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16.0).isActive = true
// add touch up target to the button
btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
// show the first question
showNextQuestion()
func showNextQuestion() -> Void
// increment currentQuestion
currentQuestion += 1
// if we are past the number of questions in this group
// set currentQuestion back to Zero and increment currentGroup
if currentQuestion == questionsPerGroup[currentGroup]
currentQuestion = 0
currentGroup += 1
// if we are past the last group, show a message
if currentGroup == questionsPerGroup.count
questionLabel.text = "End of quiz"
else
// get the question ID from the shuffled IDs of the current group
let idx = arrayOfIDs[currentGroup][currentQuestion]
// get that question object from the array
let thisQuestion = arrayOfQuestions[currentGroup][idx]
// get the question parts
let sQuestion = thisQuestion.Question ?? "missing data"
let aAnswers = thisQuestion.Answers ?? ["missing data"]
let iAnswer = thisQuestion.Answer ?? -1
// show them in our label
questionLabel.text = "\nThis is Question: \(currentQuestion + 1) of Group: \(currentGroup + 1)\n\n" +
"\(sQuestion)\n" +
"\(aAnswers)\n" +
"\(iAnswer)\n"
func didTap(_ sender: Any?) -> Void
showNextQuestion()
let vc = TestViewController()
vc.view.backgroundColor = .blue
PlaygroundPage.current.liveView = vc
【讨论】:
如果我像我一样将所有问题附加到一个数组中,然后执行 8 个 if 语句并说在第一个“if”上过滤所有包含“group1”的元素并只选择 8 个元素从那里开始,为其他组做同样的事情。你听起来怎么样? 对于 group2 选择 5 个元素等,直到我达到 50 个元素。 您需要第 1 组中的 8 个、第 2 组中的 5 个、第 3 组中的 5 个、第 4 组中的 6 个等等......?还是您只需要 50 个随机问题,所以您可能有 1 组中的 1 个、第 2 组中的 0 个、第 3 组中的 17 个等?以上是关于测验应用程序从 8 组问题中随机选择问题?的主要内容,如果未能解决你的问题,请参考以下文章