Konstantinos Natsios
Konstantinos Natsios

Reputation: 2924

Combine two arrays to form Table with Sections in Swift

I have those two structs in swift

struct Objects {
    var sectionName: String!
    var sectionObjects: [Brands]!
}

struct Brands {
    var id: String!
    var name: String!
}

And those three empty arrays

lazy var sortedLetters = [String]()
lazy var sortedBrands = [Brands]()
lazy var objectBrands = [Objects]()

The sortedLetters array is for making the headers in the tableview.

The sortedBrands is an array of brands, in which i'm trying to populate the brand's name if the letter is the same as the sortedLetters array.

The objectBrands is an array of objects in which as you will see in the tableview functions, i get the data of Brands and the header's letter.

 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            return requests.objectBrands[section].sectionName
    }

    func numberOfSections(in tableView: UITableView) -> Int {
            return objectBrands.count
    }

    func sectionIndexTitles(for tableView: UITableView) -> [String]? {
            return sortedLetters

    }

    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
                let header = view as! UITableViewHeaderFooterView
                header.textLabel?.font = UIFont(name: "Helvetica", size: 11)
                header.textLabel?.textColor = .black
                header.contentView.backgroundColor = .darkGray
    }

    func tableView(_ tableView: UITableView,
                   heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 70

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return requests.objectBrands[section].sectionObjects.count
    }

And in this for loop I'm trying to append brands inside eacher letter of the array sortedLetters.

for startNames in self.sortedLetters {
  self.objectBrands.append(Objects(sectionName: startNames, sectionObjects: self.sortedBrands))
}

Although it appends ALL Brands. And inside my table view i have something like this

Header : "A" Cells : All brands Header : "B" Cells : All brands Which is normal cause i'm missing something in my for loop.

How can i change my for loop in swift syntax, so it can append for example in letter "A" each brand name which starts with "A" ?

So it will show something like this

Header : "A" Cells : Brands that start with A Header : "B" Cells : Brands that start with B etc...

Thanks a lot!

Upvotes: 0

Views: 1061

Answers (3)

Josh Homann
Josh Homann

Reputation: 16327

Use a dictionary for your sections where the key is the letter for the section heading and the value is an array containing your models for that section. You will need to separately sort your keys (or simply precompute and store your sortedKeys in an array; you need to do this every time the data changes if you want a sparse dictionary (i.e. you only show headers for sections with items, or just once if you want to show all the headers irrespective of whether or not they are empty).

var sections: [String: [ModelType]] = [:]

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sortedSectionKeys[section]  // sortedSectionKeys = sections.keys.sorted {$0.0 < $0.1}
}

func numberOfSections(in tableView: UITableView) -> Int {
        return sections.keys.count
}

func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return sortedSectionKeys

}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[sortedSectionKeys[section]]?.count ?? 0
}

Upvotes: 1

creeperspeak
creeperspeak

Reputation: 5523

You can filter your sortedLetters array by first letter like this:

sortedLetters.filter({ $0.substring(to: $0.index($0.startIndex, offsetBy: 1)).lowercased() == "a" })

This will show only brands that being with "a" (lower case or upper case), for example. You can replace that "a" with whichever variable you're using to determine which section you're in.

Upvotes: 1

antonio081014
antonio081014

Reputation: 3593

// Iterate each Header Name for startNames in self.sortedLetters { // Filter out the brands which name starts with startNames // Here, I also sorted the brand by its name. let brands = self.sortedBrands.filter() {$0.name.hasPrefix(startNames)}.sorted(by: {$0.name < $1.name}) self.objectBrands.append(Objects(sectionName: startNames, sectionObjects:brands)) }

Upvotes: 2

Related Questions