2

I want to write an extension which allows me to put in an array and return a set number of elements from that array with no repeated items. How would I do that? This is what I have so far but it is not perfect. It does not consider duplicates and it does not seem like the best way for this to be done. I was thinking it might make sense to use a set for duplicates.

extension Array { 
    func randomElement(numberOfItems:Int) -> [Element]  {
        var finalReturn = Array()
        for i in 0..<numberOfItems {
            finalReturn.append(self[Int(arc4random_uniform(UInt32(self.count)))])
        }
        return finalReturn
    }
}

usage should be like this.

let selected = allData.randomElement(numberOfItems: 10)
Hamish
  • 78,605
  • 19
  • 187
  • 280
Nevin Jethmalani
  • 2,726
  • 4
  • 23
  • 58

1 Answers1

0

Here is one way to do it:

extension Array {
    func randomElements(number: Int) -> [Element] {
        guard number > 0 else { return [Element]() }
        var remaining = self
        var chosen = [Element]()
        for _ in 0 ..< number {
            guard !remaining.isEmpty else { break }
            let randomIndex = Int(arc4random_uniform(UInt32(remaining.count)))
            chosen.append(remaining[randomIndex])
            remaining.remove(at: randomIndex)
        }
        return chosen
    }
}

Sample:

let testArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let randomThree = testArray.randomElements(number: 3)
// randomThree is [1, 5, 4]

Depending on your use case, you may want to change the behavior when the number of elements requested is greater than the number of elements in the array.

In my sample above, if this is the case, I return the maximum number of elements possible (the number of elements in the original array). Alternatively, you could give an error or return nil.

nathangitter
  • 9,607
  • 3
  • 33
  • 42