0

I am trying to grab 2 random values that are not the same in a string like this

    var players = ["Jack, John, Michael, Peter"]
    var playersArray = ["\(players.randomElement) and \(players.randomElement) has to battle")

How am i to do this, so it grabs 2 different values?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Thuesen
  • 29
  • 4
  • 1
    Note that `players` in your code has only one string – ielyamani Oct 27 '18 at 22:04
  • The supposedly duplicate question that was linked does not address the issue of fetching a non-repeating element. – Duncan C Oct 27 '18 at 22:20
  • 3
    @DuncanC: Are you sure? The `choose(_ n: Int)` method from https://stackoverflow.com/a/27261991/1187415 picks `n` random elements with distinct indices from the array. Unless the array itself has duplicates, that gives `n` distinct random elements. – Martin R Oct 27 '18 at 22:48
  • ... and other solutions form the thread work as well, of course. – Martin R Oct 27 '18 at 23:06
  • @MartinR Maybe they have interpreted the question to need uniqueness in value. I've moved my answer to [here](https://stackoverflow.com/a/53027138/2907715). – ielyamani Oct 27 '18 at 23:28
  • 1
    Note that in your sample code `players` is not an array. It should be written `var players = ["Jack", "John", "Michael", "Peter"]` – Duncan C Oct 28 '18 at 01:00
  • 1
    @DuncanC it is an array, with one string in it – ielyamani Oct 28 '18 at 07:55

1 Answers1

0

A while back I created a class RandomObjects that maintained an array of objects and could be used to serve up random, non-repeating objects from the array one at a time. It works by maintaining an array of indexes and removing an index from the indexes array until it's depleted.

It even has a provision to "refill" the indexes after all the values have been returned, and logic to avoid the same value from being returned after the indexes array is refilled.

It was written in Swift 2, but I just updated it to Swift 4 and posted it to GitHub:

https://github.com/DuncanMC/RandomObjects.git

The class is defined like this:

class RandomObjects<T> {
    var objectsArray: [T]
    var indexes: [Int]!
    var oldIndex: Int?

The key bit of code from that class is this function:

public func randomObject(refillWhenEmpty: Bool = true) -> T? {
    var randomIndex: Int
    var objectIndex: Int

    if refillWhenEmpty {
        fillIndexesArray()
    } else if indexes.isEmpty {
        return nil
    }
    repeat {
        randomIndex = Int(arc4random_uniform(UInt32(indexes.count)))
        objectIndex = indexes[randomIndex]
    } while objectIndex == oldIndex

    indexes.remove(at: randomIndex)

    oldIndex = objectIndex
    return objectsArray[objectIndex];
}

The check for objectIndex == oldIndex is only needed when you have gone through every object in the array and have just repopulated the indexes array. It makes sure you don't repeat the last entry.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • 1
    I wonder why did you reopen this question and why did you ignore Martin R question about it. – Leo Dabus Oct 28 '18 at 02:41
  • When reviewing the linked question & answers I missed the function `choose(_ n:)`, which as Martin points out does solve the specific problem the OP posed. Had I seen that I would not have re-opened the question. Once it was re-opened, I thought there was value in posting an answer that lets you fetch random, unique items from an array one at a time. Since I had already created such a solution previously, I thought some might find it helpful. – Duncan C Oct 28 '18 at 13:45