测验应用程序从 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 组问题中随机选择问题?的主要内容,如果未能解决你的问题,请参考以下文章

Python实践练习:生成随机的测验试卷文件

Discord python 随机调查/测验

当用户从颤动的单选按钮组中选择单选按钮时如何保存数据?

如何使用 PHP、MySQL 和 Jquery 创建测验

python实践项目八:生成随机试卷文件

如何从数据库中获取随机问题包括类别?