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



我有一个字符串数组。我想随机显示此数组中的 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 个事实?

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

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

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())
}

即使它使用重复...while 语句,重复条件永远不会连续触发两次,因为除非在重新填充索引数组之后,否则您永远不会得到重复。

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

版本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

您的计时器正在调用随机事实,它只是返回一个事实,不执行任何操作。您可能应该有第三个称为 initializeTimer 的方法,它执行 Timer.scheduledtimer,您应该将其从 updateUI 方法中取出。 该计时器应调用更新UI。 这将修复您的标签更新问题。此外,您还可以在viewDidLoad中调用initializeTime,而不是updateUI。至于防止事实重复,Duncan C 的想法是拥有一个单独的数组,您可以在设置新的随机事实时从中删除项目,然后在它为空时填充回来,这似乎是一个好主意。

维护随机字符串的两个数组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
}

最新更新