2

I have a VC with a tableView inside where i fill manually an array by multiple selecting of items from my tableView's rows. In this VC i have an array

var list : [QCategoryy] = [QCategoryy]()
list = NearbyPlaces.getCategories()

where getCategories() is

static func getCategories() -> [QCategoryy] {
        let list:[QCategoryy] = [QCategoryy(name: "bar", image: UIImage(named: "bar_button.png")!), QCategoryy(name :"night_club", image: UIImage(named: "nightclub_button.png")!), QCategoryy(name: "movie_theater", image: UIImage(named: "cinema_button.png")!), QCategoryy(name: "restaurant", image: UIImage(named: "restaurant_button.png")!), QCategoryy(name: "gym", image: UIImage(named: "gym_button.png")!), QCategoryy(name: "spa", image: UIImage(named: "spa_button.png")!), QCategoryy(name: "museum", image: UIImage(named: "museum_button.png")!)]
        return list
    }

these items (bar, gym, spa etc.) will fill my tableView cells and when i select them i'll create my array selectedCategories how you can see here:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == nearbySearchSegueIdentifier {
            let selectedCategories: [QCategoryy] = tableView.indexPathsForSelectedRows?.map({ (indexPath) -> QCategoryy in
                return list[indexPath.row] }) ?? []

            if let selectedRows = tableView.indexPathsForSelectedRows {

                if let vc : nextClass = segue.destination as? nextClass {


                vc.categories = selectedCategories


            }
        }
    }
}

now i would like to know how can i fill this array (selectedCategories) without selecting the cells of the tableView but in random way by pressing a button, so i want to fill the array with random items of my var list : [QCategoryy] = [QCategoryy]() with a button tap, how can i do?

UPDATE

struct QCategoryy {
    var name: String
    var image: UIImage
    var isSelected = false

    init(name:String, image:UIImage) {
        self.name = name
        self.image = image

    }
}

extension QCategoryy: ExpressibleByStringLiteral {


    init(stringLiteral value: String) {
        self.name = value
        self.image = UIImage()

    }
    init(unicodeScalarLiteral value: String) {
        self.init(name: value, image: UIImage())
    }
    init(extendedGraphemeClusterLiteral value: String) {
        self.init(name: value, image: UIImage())
    }
}
arc4Random
  • 101
  • 11

1 Answers1

1

The route you likely want to go is to "shuffle" the array of categories, and then take the first n number of elements from the array.

Say you have an array of numbers 1 through 10:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

and you want to get 6 random elements. If you simply did a Get Random Element type of call 6 times, you would very likely end up with duplicates.

So, if you perform a Shuffle on the array, your new array may look like this:

[7, 2, 9, 5, 3, 4, 1, 10, 8, 6]

and you can get the first 6 elements - which will be random without duplicates.

The elements can be anything... I'm just showing numbers here for explanation.


Edit

For example... add this code to your project:

extension MutableCollection where Indices.Iterator.Element == Index {
    /// 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(arc4random_uniform(numericCast(unshuffledCount)))
            guard d != 0 else { continue }
            let i = index(firstUnshuffled, offsetBy: d)
            swap(&self[firstUnshuffled], &self[i])
        }
    }
}

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

Then, in prepare for segue, you could do:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == nearbySearchSegueIdentifier {
            if let vc : nextClass = segue.destination as? nextClass {

                // use ALL QCategoryy objects, in random order
                vc.categories = NearbyPlaces.getCategories().shuffled()

                // or, use 4 random QCategoryy objects
                //vc.categories = NearbyPlaces.getCategories().shuffled()[0...3]

            }
        }
    }
}

This shuffle extension, and others, can be found here: https://stackoverflow.com/a/24029847/6257435

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • ok understand, and this is your example [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] with an array of numbers, to write instead an array with the elements of categories? – arc4Random Nov 15 '17 at 14:22
  • Yes - if you look at the shuffle code in the link, you will see that it shuffles whatever the objects are in the array - it doesn't matter whether it's an array of numbers, buttons, views, custom objects, etc. – DonMag Nov 15 '17 at 14:29
  • ok so in my case i have to copy and paste that code using with my list? – arc4Random Nov 15 '17 at 14:42
  • ah ok i have to modify the prepare in the end, now it's all clear, thank you – arc4Random Nov 15 '17 at 15:12