在iOS中随机显示字符串而不重复它们 [英] Displaying strings in iOS randomly without repeating them

查看:113
本文介绍了在iOS中随机显示字符串而不重复它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个测验应用。该应用程序使用.json文件作为问题和答案的数据库。这个.json文件如下所示......

  {
id:1,
问题:地球是:,
答案:[
星球,
流星,
星际,
小行星
],
难度:1
}

...只是继续讨论500多个问题。



我使用以下代码随机显示问题:

  let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestion(randomNumber)

这项工作很好,但因为它随机选择问题我发现问题经常重复(即使我有500多个问题!)。 / p>

我对此进行了广泛的研究,并认为我读得太多,因为我现在很困惑。我读过关于播种的内容,关于保存所提问题的索引,并尝试使用NSUserDefault。



简而言之,我如何修改我的代码来实现一个取而代之的是以下结果:


  1. 根本不重复任何问题,但在所有问题都被问过一次时停止提问;

  2. 与上面的1类似,但是用户设置了问题的数量而不是询问数据库中的所有问题;

  3. 不重复在所有问题都被提出之前,任何问题都可以;或者,

  4. 不重复之前已正确回答的任何问题,但可能会重复那些回答不正确的问题。

以下是我认为相关的代码位:

  LoadAllQuestionsAndAnswers()

let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestion(randomNumber)


func LoadAllQuestionsAndAnswers()
{
let path = NSBundle.mainBundle()。pathForResource(content,ofType:json)
let jsonData:NSData = NSData(contentsOfFile:path!)!
allEntries =(尝试!NSJSONSerialization.JSONObjectWithData(jsonData,options:NSJSONReadingOptions.MutableContainers))as! NSArray
// println(allEntries)

}


func LoadQuestion(index:Int)
{
let entry :NSDictionary = allEntries.objectAtIndex(index)as! NSDictionary
让问题:NSString = entry.objectForKey(问题)为! NSString
让arr:NSMutableArray = entry.objectForKey(answers)为! NSMutableArray

// println(问题)
// println(arr)

labelQuestion.text =问题为字符串

let indices :[Int] = [0,1,2,3]
//让newSequence = shuffle(indices)
let newSequence = indices.shuffle()
var i:Int = 0
for(i = 0; i< newSequence.count; i ++)
{
let index = newSequence [i]
if(index == 0)
{
//我们需要存储正确的答案索引
currentCorrectAnswerIndex = i

}

让answer = arr.objectAtIndex(index)为! NSString
switch(i)
{
case 0:
buttonA.setTitle(answer as String,forState:UIControlState.Normal)
break;

case 1:
buttonB.setTitle(answer as String,forState:UIControlState.Normal)
break;

case 2:
buttonC.setTitle(answer as String,forState:UIControlState.Normal)
break;

case 3:
buttonD.setTitle(answer as String,forState:UIControlState.Normal)
break;

默认值:
break;
}



}
buttonNext.hidden = true
//我们需要重置按钮才能重新启用它们
ResetAnswerButtons()

}



@IBAction func PressedButtonNext(发送者:UIButton){
print(按钮下一步按下 )
let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestion(randomNumber)

}


解决方案

如果我理解你的要求:




  • 您希望在View Controller实例和应用程序启动之间保留随机生成的数字

  • 您永远不想重复任何问题



实现此目的的一种快速方法是使用 NSUserDefaults 来跟踪来自您的(伪)随机数的顺序和值PRNG。通过这种方式,您可以通过重放以前的骰子卷来实例化即时问题的数组,并按照正确的顺序从池中删除这些问题。



这也可以让你将PRNG作为一个黑盒子处理,不关心播种和重播。



此外,请确保从当前池中删除任何骰子掷骰子中的任何选定问题。



旁注:您没有遵循命名约定 - 例如,函数将以小写字母开头。



为了您自己的良好和可读性,请遵循流行的惯例,至少在与他人共享您的代码时。更好的是,所有的时间。



编辑



更加详细:




  • NSUserDefaults 可以轻松地为您节省少量数据。如果你只想记住一组数字',那么它就是最好的选择。

  • 假设你的数据在一个实例变量中是helt,如下所示:

      var questions:[问题] = //加载问题 - 请仔细阅读,见下文。 

    您可以轻松删除PSNG的问题( p seudo- r andom n umber g enerator)选择如下:

      let randomNumber = Int(arc4random_uniform(UInt32(questions.count)))
    questions.removeAtIndex(randomNumber)

    因此,下一个骰子掷骰(例如你的PSNG的调用)保证不会选择已经问过的问题,因为它不再是它所选择的可用问题池。


  • 这种方法确实需要您以正确的顺序保存所有随机数,以重放实例化新实例之前发生的事情(例如,因为应用程序已经重新开放)。这就是 NSUserDefaults ' setObject:forKey: objectForKey : 在最初加载问题并记住每个新骰子时都会发挥作用。




我希望,这涵盖了你之前可能不理解的内容。


I'm making a quiz app. The app uses a .json file as the 'database' of questions and answers. This .json file looks as follows...

      {
        "id" : "1",
        "question": "Earth is a:",
             "answers": [
            "Planet",
            "Meteor",
            "Star",
            "Asteroid"
          ],
          "difficulty": "1"
      }

...and just keeps going for over 500 questions.

I display the questions randomly by using the following code:

    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
    LoadQuestion(randomNumber)

This work fine, but because it selects the questions randomly I'm finding that questions are repeating too regularly (even though I have over 500 questions!).

I've researched this extensively and think perhaps I've read too much as I'm now quite confused. I've read about 'seeding', about saving an index of questions asked, and trying to use NSUserDefault.

In short, how can I modify my code to achieve one of the following outcomes instead:

  1. To not repeat any questions at all, but to stop asking questions when all questions have been asked once;
  2. Similar to 1 above, but have the number of questions being asked set by the user rather than asking all questions in the database;
  3. To not repeat any questions at all until all questions have been asked first; or,
  4. To not repeat any questions that have previously been answered correctly, but those that were answered incorrectly may be repeated.

Below is what I think are the relevant bits of code:

    LoadAllQuestionsAndAnswers()

    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
    LoadQuestion(randomNumber)


func LoadAllQuestionsAndAnswers()
{
    let path = NSBundle.mainBundle().pathForResource("content", ofType: "json")
    let jsonData : NSData = NSData(contentsOfFile: path!)!
    allEntries = (try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)) as! NSArray
    //println(allEntries)

}


func LoadQuestion(index : Int)
{
    let entry : NSDictionary = allEntries.objectAtIndex(index) as! NSDictionary
    let question : NSString = entry.objectForKey("question") as! NSString
    let arr : NSMutableArray = entry.objectForKey("answers") as! NSMutableArray

    //println(question)
    //println(arr)

    labelQuestion.text = question as String

    let indices : [Int] = [0,1,2,3]
    //let newSequence = shuffle(indices)
    let newSequence = indices.shuffle()
    var i : Int = 0
    for(i = 0; i < newSequence.count; i++)
    {
        let index = newSequence[i]
        if(index == 0)
        {
            // we need to store the correct answer index
            currentCorrectAnswerIndex =  i

        }

        let answer = arr.objectAtIndex(index) as! NSString
        switch(i)
        {
        case 0:
            buttonA.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 1:
            buttonB.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 2:
            buttonC.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        case 3:
            buttonD.setTitle(answer as String, forState: UIControlState.Normal)
            break;

        default:
            break;
        }



    }
    buttonNext.hidden = true
    // we will need to reset the buttons to reenable them
    ResetAnswerButtons()

}



@IBAction func PressedButtonNext(sender: UIButton) {
    print("button Next pressed")
    let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
    LoadQuestion(randomNumber)

}

解决方案

If I understand your requirements correctly:

  • You want to persist the randomly generated numbers between View Controller instances and application launches
  • you never want to repeat any question

A quick way to achieve this is to use NSUserDefaults to keep track of the order and value of (pseudo)random numbers from your PRNG. This way, you can instantiate the array of avaiable questions on instantaition by replaying previous dice rolls, removing those questions from the pool alongside in the right order.

This also lets you handle the PRNG as a black box, not caring about seeding and replay.

Also, make sure to remove any chosen questions from the current pool for any dice roll.

Side note: You are not following naming conventions - functions are to be starting lower case, for example.

For your own good and readability, please follow prevalent conventions, at least when sharing your code with others. Better yet, all the time.

Edit:

To be more verbose:

  • NSUserDefaults can save small amounts of data for you in an easy way. If you 'just want to remember an array of numbers', it's the go to place.
  • suppose your data is helt in an instance variable like so:

    var questions : [Question] = // load the questions - carefully, see below.
    

    you can easily remove the question your PSNG (pseudo-random number generator) selects like so:

    let randomNumber = Int(arc4random_uniform(UInt32(questions.count)))
    questions.removeAtIndex(randomNumber)
    

    Thus the next dice roll (e.g. invocation of your PSNG) is guaranteed not to select the question already asked because it is no longer in the pool of avaiable questions it selects from.

  • This approach does need you to save all your random numbers in the right order to 'replay' what has happened before when you are instantiating a new instance (for example, because the app has been reopened). That's where NSUserDefaults' setObject:forKey: and objectForKey: come into play when loading the questions initially and 'remembering' every new dice roll.

I hope, this covers what you might didn't understand before.

这篇关于在iOS中随机显示字符串而不重复它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆