从计时器上的数组中提取随机项

时间:2017-07-24 19:41:30

标签: ios arrays swift nstimer

我有一个字符串数组。我想随机地从这个数组中显示3个独特的项目。然后每5秒,其中一个项目被另一个唯一项目替换(我的想法是添加一个延迟的动画)。

我可以显示3个字符串,但有时它们会重复,而计时器不会更新factLabel标签。

这是我的进步:

override func viewDidLoad() {
    super.viewDidLoad()
    updateUI()
}

func randomFact() -> String {
    let arrayCount = model.cancunFacts.count
    let randomIndex = Int(arc4random_uniform(UInt32(arrayCount)))
    return model.cancunFacts[randomIndex]
}

// Display the facts
func updateUI() {
    Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(randomFact), userInfo: nil, repeats: true)
    factLabel.text = randomFact() + " " + randomFact() + " " + randomFact()
}

如何让文字随机更新,而不重复3个事实?

3 个答案:

答案 0 :(得分:3)

创建索引数组。从数组中删除一个随机索引,用它来索引你的字符串。当索引数组为空时,重新填充它。

以下是一些生成随机,非重复字符串的示例代码:

var randomStrings = ["Traitor", "Lord Dampnut", "Cheeto-In-Chief", 
  "F***face Von Clownstick", "Short-Fingered Vulgarian", 
  "Drumpf", "Der Gropenführer", "Pumpkin in a suit"]

var indexes =  [Int]()

func randomString() -> String {
    if indexes.isEmpty {
        indexes = Array(0...randomStrings.count-1)
    }
    let index = Int(arc4random_uniform(UInt32(indexes.count)))
    let randomIndex = indexes.remove(at: index)
    return randomStrings[randomIndex]
}

for i in 1...100 {
    print (randomString())
}

(请注意,当索引数组为空且需要重新填充时,它仍然可能会生成重复的字符串。您需要添加额外的逻辑来防止这种情况。)

版本2:

以下是相同的代码,稍微修改以避免在索引数组为空且需要重新填充时重复:

var randomStrings = ["tiny-fingered", "cheeto-faced", "ferret-wearing", "sh*tgibbon"]

var indexes =  [Int]()
var lastIndex: Int?

func randomString() -> String {
    if indexes.isEmpty {
        indexes = Array(0...randomStrings.count-1)
    }
    var randomIndex: Int
    repeat {
        let index = Int(arc4random_uniform(UInt32(indexes.count)))
        randomIndex = indexes.remove(at: index)
    } while randomIndex == lastIndex
    lastIndex = randomIndex
    return randomStrings[randomIndex]
}


for i in 1...10000 {
    print (randomString())
}

即使它使用了repeat ... while语句,重复条件也不会连续两次触发,因为除了重新填充索引数组之外,你永远不会重复。 / p>

使用该代码,如果存在重复,则在通过该数组时将跳过所选字符串。为了避免这种情况,您需要稍微调整代码,以便在验证数据不是重复之前不从数组中删除给定索引。

版本3:

上面的版本2,如果在重新填充数组时选择重复,则会跳过一个条目。我写了第三个版本的代码,重新填充数组,删除它返回的最后一项,以便它不能重复,然后在它挑选一个随机项后将其添加回数组。第三个版本将始终返回源数组中的每个项目,然后重新填充它,并且也永远不会重复项目。因此,它是真正随机的,没有偏见:

import UIKit

var randomStrings = ["Traitor", "Lord Dampnut", "Cheeto-In-Chief",
                     "F***face Von Clownstick", "Short-Fingered Vulgarian",
                     "Drumpf", "Der Gropenführer", "Pumpkin in a suit"]

var indexes =  [Int]()
var lastIndex: Int?
var indexToPutBack: Int?

func randomString() -> String {

  //If our array of indexes is empty, fill it.
  if indexes.isEmpty {
    indexes = Array(0...randomStrings.count-1)
    print("") //Print a blank line each time we refill the array so you can see

    //If we have returned an item previously, find and remove that index
    //From the refilled array
    if let lastIndex = lastIndex,
      let indexToRemove = indexes.index(of: lastIndex) {
      indexes.remove(at: indexToRemove)
      indexToPutBack = indexToRemove //Remember the index we removed so we can put it back.
    }
  }
  var randomIndex: Int
  let index = Int(arc4random_uniform(UInt32(indexes.count)))
  randomIndex = indexes.remove(at: index)

  //If we refilled the array and removed an index to avoid repeats, put the removed index back in the array
  if indexToPutBack  != nil{
    indexes.append(indexToPutBack!)
    indexToPutBack = nil
  }
  lastIndex = randomIndex
  return randomStrings[randomIndex]
}


for i in 1...30 {
  print (randomString())
}

示例输出:

Short-Fingered Vulgarian
F***face Von Clownstick
Pumpkin in a suit
Drumpf
Lord Dampnut
Traitor
Der Gropenführer
Cheeto-In-Chief

Der Gropenführer
Drumpf
Lord Dampnut
Short-Fingered Vulgarian
Cheeto-In-Chief
Pumpkin in a suit
Traitor
F***face Von Clownstick

Short-Fingered Vulgarian
F***face Von Clownstick
Drumpf
Traitor
Cheeto-In-Chief
Lord Dampnut
Pumpkin in a suit
Der Gropenführer

Lord Dampnut
Short-Fingered Vulgarian
Pumpkin in a suit
Cheeto-In-Chief
Der Gropenführer
F***face Von Clownstick

答案 1 :(得分:0)

你的计时器正在调用随机事实,它只是返回一个事实,并没有做任何事情。你可能应该有一个名为initializeTimer的第三个方法来执行Timer.scheduledtimer,你应该从你的updateUI方法中取出它。该计时器应该调用updateUI。这将修复您的标签更新。您还可以在viewDidLoad中调用initializeTimer而不是updateUI。至于防止重复事实,Duncan C的想法就是设置一个单独的数组,当你设置新的随机事实时你从中删除项目,然后在空的时候重新填充它似乎是一个好主意。 / p>

答案 2 :(得分:0)

最简单的方法是维护两个随机字符串数组usedStringsunusedStrings,如下所示:

var unusedStrings: [String] = ["king", "philip", "calls", "out", "for", "good", "soup"]
var usedStrings: [String] = []

func randomString() -> String {
    if unusedStrings.isEmpty() {
        unusedStrings = usedStrings
        usedStrings = []
    }

    let randomIndex = Int(arc4random_uniform(unusedStrings.count))
    let randomString = unusedStrings[randomIndex]
    usedStrings.append(randomString)

    return randomString
}