3

I am attempting to substitute arc4random in linux using the randr function from Glibc. Although I managed to shuffle an Array of integers, I failed to do so with an Array of string.

The code below works as expected:

import Foundation

extension MutableCollection {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            let d: IndexDistance = numericCast(Int(random() % numericCast(unshuffledCount) + 1 ))
            let i = index(firstUnshuffled, offsetBy: d)
            swapAt(firstUnshuffled, i)
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

let x = [1, 2, 3].shuffled()
print(x)
// [3, 1, 2]

But if I do the same to an Array of string:

let fiveStrings = ["20", "45", "70", "30"].map(String.init).shuffled()
print(fiveStrings)

It fails with Index out of range. The error is the same with

var numbers = [1, 2, 3, 4]
print(numbers.shuffle())
  • How do I shuffle the strings using random()?
lf_araujo
  • 1,991
  • 2
  • 16
  • 39

1 Answers1

3

The code

 let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))

in How do I shuffle an array in Swift? creates a random number in the between 0 and unshuffledCount-1. To achieve the same with random() use

 let d: IndexDistance = numericCast(Int(random() % numericCast(unshuffledCount)))

without the +1.

Note that in contrast to arc4random_uniform():

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thank you for the thorough answer. I know about the modulo bias, but that has to do for now. How do I solve the problem in the line: `var numbers = [1, 2, 3, 4]; print(numbers.shuffle())`? – lf_araujo Nov 06 '17 at 06:29
  • What problem? `shuffle()` has no return value, it mutates the argument. What you probably want is `var numbers = [1, 2, 3, 4] ; numbers.shuffle() ; print(numbers)` – Martin R Nov 06 '17 at 06:30