Problems with randomisation when appending to an array

I have an array of horses that I am appending with the following code with a UIButton:

Code Block
myHorses.append(Horse(
            name: "New Horse",
            gender: ["Mare", "Stallion"][Int.random(in:0...1)],
            age: Int.random(in:1...19)
)

This is the array I am adding to:

Code Block
var myHorses = [
    Horse(name: "Donnerhall", gender: "Stallion", age: 5
]


I can add a random horse to the array, but if I click it again it adds the same horse again. I want it to be so that every time I click it, a new, different horse appears in the array. If I restart the app, though, I get a new horse when I click the button the first time (but the same if I click it again)


Answered by imey in 634117022
I think I solved the issue. I added an ID number to each new horse, making all the names unique. Now each new horse is random and also has an ID number.
I made a property :
Code Block
var horsesCreated = 2


then each new horse got the property
Code Block
idNumber: (horsesCreated+1)


and the buyHorseButton is assigned to do this after creating a horse;
Code Block
horsesCreated += 1

I know this maybe isn't the cleanest fix, but I am really happy it's working. Couldn't have done it without your input! Thanks for your patience :)

if I click it again it adds the same horse again.

Please show enough code to reproduce the issue.

With the currently given code, I cannot reproduce the issue you described.
At each time I tap the button, a random horse is added to the array.
Code Block
import UIKit
class ViewController: UIViewController {
var myHorses = [
Horse(name: "Donnerhall", gender: "Stallion", age: 5)
]
@IBAction func buttonPressed(_ sender: Any) {
myHorses.append(Horse(
name: "New Horse",
gender: ["Mare", "Stallion"][Int.random(in:0...1)],
age: Int.random(in:1...19)
))
print(myHorses)
}
}

Output:
Code Block
[Horse(Donnerhall, Stallion, 5), Horse(New Horse, Mare, 19)]
[Horse(Donnerhall, Stallion, 5), Horse(New Horse, Mare, 19), Horse(New Horse, Mare, 4)]
[Horse(Donnerhall, Stallion, 5), Horse(New Horse, Mare, 19), Horse(New Horse, Mare, 4), Horse(New Horse, Mare, 13)]


The same: do you mean age is also the same ?
It's very long, so I'm unable to post the portion from the model... If the mini-version I sent before is working, though, I may be able to just add bits until I find the problem :)

View controller:
Code Block
import UIKit
class HorseSalesViewController: UIViewController {
    @IBOutlet weak var timeOutlet: UILabel!
    @IBOutlet weak var cashOutlet: UILabel!
    
    @IBOutlet weak var saleConfirmOutlet: UILabel!
    @IBOutlet weak var horsePriceOutlet: UILabel!
  
    override func viewDidLoad() {
    super.viewDidLoad()
      cashOutlet.text = "Cash: \(cash)"
        timeOutlet.text = "Time: \(time)"
        horsePriceOutlet.text = "Cost: \(foundationHorsePrice)"
    }
    
    let bayRandom = bayArray.randomElement()
    let blackRandom = blackArray.randomElement()
    let buckskinRandom = buckskinArray.randomElement()
    let chestnutRandom = chestnutArray.randomElement()
    let cremelloRandom = cremelloArray.randomElement()
    let dunRandom = dunArray.randomElement()
    let perlinoRandom = perlinoArray.randomElement()
    let smokyBlackRandom = smokyBlackArray.randomElement()
    let smokyCreamRandom = smokyCreamArray.randomElement()
    let greyRandom = greyArray.randomElement()
    let overoRandom = overoArray.randomElement()
    let palominoRandom = palominoArray.randomElement()
    let roanRandom = roanArray.randomElement()
    let sabinoRandom = sabinoArray.randomElement()
    let maxSabinoRandom = maxSabinoArray.randomElement()
    let tobianoRandom = tobianoArray.randomElement()
    let headMarkingsRandom = headMarkingsArray.randomElement()
    let legMarkingsRandom = legMarkingsArray.randomElement()
    let blankImage =  imageLiteral(resourceName: "Blank image")
    
    @IBAction func buyHorseButton(_ sender: UIButton) {
        if cash > foundationHorsePrice {
        cash -= foundationHorsePrice
        saleConfirmOutlet.text = "Congratulations on your new horse!"
        cashOutlet.text = "Cash:\(cash)"
        myHorses.append(Horse(
            //Base stats
            name: "New Horse",
            gender: ["Mare", "Stallion"][Int.random(in:0...1)],
            age: Int.random(in:1...19),
            focus: Int.random(in:10...100),
            health: Int.random(in:1...100),
            points: 0,
            level: "Intro",
            weight: Int.random(in:450...650),
            reactivity: Int.random(in:1...100),
            //Conformation
            head: ["Poor", "Substandard", "Average", "Good", "Excellent"][Int.random(in:0...4)],
            neck: ["Poor", "Substandard", "Average", "Good", "Excellent"][Int.random(in:0...4)],
            back: ["Poor", "Substandard", "Average", "Good", "Excellent"][Int.random(in:0...4)],
            legs: ["Poor", "Substandard", "Average", "Good", "Excellent"][Int.random(in:0...4)],
            hindquarters: ["Poor", "Substandard", "Average", "Good", "Excellent"][Int.random(in:0...4)],
        
            //Pedigree
            sire: "Unknown",
            dam: "Unknown",
            
            //Training
            rhythm: 0,
            looseness: 0,
            contact: 0,
            impulsion: 0,
            straightness: 0,
            collection: 0,
          
            //Genotype
            ext: ["E", "e"][Int.random(in:0...1)]+["E", "e"][Int.random(in:0...1)],
            ago: ["A", "a"][Int.random(in:0...1)]+["A", "a"][Int.random(in:0...1)],
            gre: ["G", "g"][Int.random(in:0...1)]+["G", "g"][Int.random(in:0...1)],
            cre: ["Cr", "cr"][Int.random(in:0...1)]+["Cr", "cr"][Int.random(in:0...1)],
            dun: ["D", "nd2"][Int.random(in:0...1)]+["D", "nd2"][Int.random(in:0...1)],
            tob: ["To", "to"][Int.random(in:0...1)]+["To", "to"][Int.random(in:0...1)],
            sab: ["SB1", "sb1"][Int.random(in:0...1)]+["SB1", "sb1"][Int.random(in:0...1)],
            roa: ["Rn", "rn"][Int.random(in:0...1)]+["Rn", "rn"][Int.random(in:0...1)],
            
            //Phenotype
            basePhenotype: chestnutRandom ??  imageLiteral(resourceName: "Blank image"),
            roanPhenotype: roanRandom ??  imageLiteral(resourceName: "Blank image.png"),
            greyPhenotype:  imageLiteral(resourceName: "Blank image.png"),
            tobianoPhenotype:  imageLiteral(resourceName: "Blank image.png"),
            sabinoPhenotype:  imageLiteral(resourceName: "Blank image.png"),
            whiteFacePhenotype:  imageLiteral(resourceName: "Blank image.png"),
            whiteLegsPhenotype:  imageLiteral(resourceName: "Blank image.png"),
            //Feed requirements
            water: 100,
            energy: 100,
            protein: 100,
            vitamins: 100,
            minerals: 100,
            chewingTime: 100))
        }
        
        if cash < foundationHorsePrice {
            saleConfirmOutlet.text = "You don't have enough cash"
        }
    
    }


You write:

but if I click it again it adds the same horse again

What is the IBAction here ? Is it buyHorseButton ?

Do you get exactly the same Horse appended ?
Could you print the array after appending, to see exactly what you get.

To check what is going on, could you change the name:
Code Block
name: "New Horse \(cash)",

by adding for instance the cash amount.
The IBAction is the buyHorseButton. I tried adding the cash value to the horseName, and the horses came up random in the simulator :). However, when I removed the cash label, they turned out the same again. Maybe horses should have an identification number to differentiate them? I wanted to make a unique ID number for each horse anyway, maybe this is a good time to implement that

the horses came up random in the simulator

How are you showing the horses in your app?

the horses came up random in the simulator

So that means that you have different Horses created, not the same one.

What is exactly the problem:
  • same horse created several times (does not seem the case)

  • they do not show randomly as you want in the table ?

You should definitely show the code where you populate the table.
Yes all the stats are the same after I remove the cash label from the name label.
Please, provide more information in your answers, you just give the minimum. That does not help to help.
  1. Please print (at line 117) the array of horses after the first and second addition. And post the result.

  2. Show the code where you populate the array

  3. Answer the other questions: What is exactly the problem:

    • same horse created several times (does not seem the case)
    • they do not show randomly as you want in the table ?
  4. We do not see where you declared myHorses. Please show.

If you cannot show full code as it is very large, can you create a minimized sample project which can reproduce the same issue and show whole code of it?

Without enough info, no one can help you solve the issue.
  1. Please print (at line 117) the array of horses after the first and second addition. And post the result.

When I add the code "print(myHorses)" and run the IBAction, the console opens but there's nothing in it. Maybe the array is too long?

2. Show the code where you populate the array
The array is populated with the buyHorseButton. There are a couple of sample horses in there already for testing purposes

3. Answer the other questions: What is exactly the problem:
- same horse created several times (does not seem the case) - this is what happens, unless I add cash to the name. Maybe the problem will go away if I assign an ID number to each horse so that they have unique names? I was meaning to do this anyway. I'm not sure why it happens but the randomisation worked with cash added to the name, but not without.
- they do not show randomly as you want in the table ? - the first horse is random, then the following horses are the same as the first one. When I close the simulator and run again, a new random horse is generated and then the following horses are clones of the first.

4. We do not see where you declared myHorses. Please show.
The list of horses are shown in their own VC (shown below), and when a horse is clicked this opens a new VC with fields that fetch data from the myHorses array

Code Block
import UIKit
class HerdViewController: UIViewController {
    @IBOutlet weak var buttonsStack: UIStackView!
  
    override func viewDidLoad() {
        super.viewDidLoad()
        
        for horse in myHorses {
            let button = UIButton()
            button.addTarget(self, action: #selector(self.lookupHorse(sender:)), for: .touchUpInside)
            button.setTitleColor(.white, for: UIControl.State.normal)
            button.setTitle(horse.name, for: UIControl.State.normal)
            
            button.backgroundColor =  colorLiteral(red: 0.005273803137, green: 0.4785152674, blue: 0.3960535526, alpha: 1)
            buttonsStack.addArrangedSubview(button)
         }
         buttonsStack.translatesAutoresizingMaskIntoConstraints = false
        
    }
    
    private var horseSelected: Horse?
    
    @objc func lookupHorse(sender: UIButton){
            let horseName = sender.title(for: .normal)
            //`lookupHorse` from `myHorses`
            if let theHorse = myHorses.first(where: {$0.name == horseName}) {
                    horseSelected = theHorse
                    self.performSegue(withIdentifier: "horseViewerSegue", sender: self)
            }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            switch segue.identifier {
            case "horseViewerSegue":
                    let horseVC = segue.destination as! HorseViewController
                    horseVC.horsePassed = horseSelected
            default:
                    print("Unknown segue: \(segue.identifier ?? "nil")")
            }
    }
    


Do you have tips on how to create ID numbers for each new horse created? I have a feeling this can solve the issue. I'll add an ID number property to the buyHorseButton and assign some numbers to the sample horses

Accepted Answer
I think I solved the issue. I added an ID number to each new horse, making all the names unique. Now each new horse is random and also has an ID number.
I made a property :
Code Block
var horsesCreated = 2


then each new horse got the property
Code Block
idNumber: (horsesCreated+1)


and the buyHorseButton is assigned to do this after creating a horse;
Code Block
horsesCreated += 1

I know this maybe isn't the cleanest fix, but I am really happy it's working. Couldn't have done it without your input! Thanks for your patience :)
Great the trick works, but that's surprising. We would need to be able to compile the whole project to understand where the issue is.

Don't forget to close the thread on the correct answer.
Problems with randomisation when appending to an array
 
 
Q