Reputation: 186
What I’m trying to do is group the sections in the TableView. By sorting them by the storeName
so that I can separate the items to go to its proper section and arranged by StoreName
.
Im trying to present a couple of different sections of items in the list for each store. By grouping the sections based on StoreName
.
The Items
Array contains all the items for each in each section and shows which store the item belongs to.
How would I be able to group the sections for specific stores?
I know that im close at grouping my sections but im just not sure how to make it work correctly as well as it connecting to my Custom HeaderCell
. I have a function written in my StoreVC
called attemptToAssembleStoreGroups()
I just want to know how would I be able to group my items together by their storeName
to have their own section for each store with its own list of items.
struct ItemSelection {
let store: String
let productName: String
let productImage: UIImage
let quantity: String
let total: String
}
struct ItemSection {
let title : String
let stores : [ItemSelection]
}
class StoreVC: UITableViewController {
fileprivate let cellId = "id123"
let items = [
ItemSelection(store: "Walmart",
productName: "Bionicle",
productImage: #imageLiteral(resourceName: "Bionicle"),
quantity: "4",
total: "24"),
ItemSelection(store: "Walmart",
productName: "PokeBall",
productImage: #imageLiteral(resourceName: "PokeBall"),
quantity: "2",
total: "30"),
ItemSelection(store: "Target",
productName: "Beer",
productImage: #imageLiteral(resourceName: "Beer"),
quantity: "2",
total: "30"),
ItemSelection(store: "Lego Store",
productName: "Star Wars Set",
productImage: #imageLiteral(resourceName: "Star_Wars_Set"),
quantity: "4",
total: "256"),
ItemSelection(store: "Lego Store",
productName: "Indiana Jones Set",
productImage: #imageLiteral(resourceName: "Indiana_Jones_Set"),
quantity: "2",
total: "88"),
ItemSelection(store: "Amazon",
productName: "Coconut Milk",
productImage: #imageLiteral(resourceName: "Coconut_Milk"),
quantity: "4",
total: "20"),
ItemSelection(store: "Amazon",
productName: "32 inch Tv",
productImage: #imageLiteral(resourceName: "TV"),
quantity: "1",
total: "156"),
ItemSelection(store: "Amazon",
productName: "Amazon Echo",
productImage: #imageLiteral(resourceName: "Amazon_Echo"),
quantity: "1",
total: "80"),
ItemSelection(store: "Amazon",
productName: "Grill",
productImage: #imageLiteral(resourceName: "Grill"),
quantity: "3",
total: "90"),
ItemSelection(store: "Amazon",
productName: "Coconut Bar",
productImage: #imageLiteral(resourceName: "coconuts"),
quantity: "4",
total: "240")
]
var itemSelection = [[ItemSelection]]()
var storeArray = [String]()
var itemSections = [ItemSection]()
override func viewDidLoad() {
super.viewDidLoad()
for index in self.items {
storeArray.append(index.store)
}
let groupedDictionary = Dictionary(grouping: items, by: {String($0.store.prefix(1))})
let keys = groupedDictionary.keys.sorted()
itemSections = keys.map{ItemSection(title: $0, stores: groupedDictionary[$0]!.sorted(by: {$0.store < $1.store}))}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return itemSections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSections[section].stores.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! StoreCell
let itemSelections = itemSelection[indexPath.section][indexPath.row]
cell.itemSelction = itemSelections
return cell
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "Header") as! HeaderCell
let stores = itemSelection[section]
cartHeader.storeName.text = "Store: \(stores)"
return cartHeader
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class StoreCell: UITableViewCell {
@IBOutlet weak var itemQty: UILabel!
@IBOutlet weak var itemName: UILabel!
@IBOutlet weak var itemPrice: UILabel!
@IBOutlet weak var itemImage: UIImage!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
var itemSelection: ItemSelection! {
didSet {
itemName.text = itemSelection.productName
itemQty.text = "Qty: \(itemSelection.quantity)"
itemPrice.text = "$\(itemSelection.total)"
itemImage.image = itemSelection.productImage
}
}
}
class HeaderCell: UITableViewCell {
@IBOutlet weak var storeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Upvotes: 1
Views: 1178
Reputation: 16735
Alternatively, you could break out your ItemSelection stuff into a separate class.
Dictionary(grouping:by:)
enables you to turn an array into a dictionary grouped by whatever key you specify. The code below groups it by store name.
I make use of lazy
vars so they're not all initialized when the class is initialized. Everything gets initialized when it's needed.
The storeNames
are retrieved from the dictionary keys.
The elements for each store are retrieved by looking up a value from the dictionary I create from the initial array.
class StoreInfoDataManager {
struct ItemSelection {
let storeName: String
let productName: String
let productImage: UIImage
let quantity: String
let total: String
}
lazy var storeDictionary: [String: [ItemSelection]] = {
return Dictionary(grouping: itemSelections) { $0.storeName }
}()
// These are the keys for your sections
lazy var storeNames: [String] = {
return Array(storeDictionary.keys).sorted()
}()
// This returns an array of items in the store
func items(for store: String) -> [ItemSelection]? {
return storeDictionary[store]
}
lazy var itemSelections: [ItemSelection] = {
return [
ItemSelection(storeName: "Walmart",
productName: "Bionicle",
productImage: #imageLiteral(resourceName: "Bionicle"),
quantity: "4",
total: "24"),
ItemSelection(storeName: "Walmart",
productName: "PokeBall",
productImage: #imageLiteral(resourceName: "PokeBall"),
quantity: "2",
total: "30"),
ItemSelection(storeName: "Target",
productName: "Beer",
productImage: #imageLiteral(resourceName: "Beer"),
quantity: "2",
total: "30"),
ItemSelection(storeName: "Lego Store",
productName: "Star Wars Set",
productImage: #imageLiteral(resourceName: "Star_Wars_Set"),
quantity: "4",
total: "256"),
ItemSelection(storeName: "Lego Store",
productName: "Indiana Jones Set",
productImage: #imageLiteral(resourceName: "Indiana_Jones_Set"),
quantity: "2",
total: "88"),
ItemSelection(storeName: "Amazon",
productName: "Coconut Milk",
productImage: #imageLiteral(resourceName: "Coconut_Milk"),
quantity: "4",
total: "20"),
ItemSelection(storeName: "Amazon",
productName: "32 inch Tv",
productImage: #imageLiteral(resourceName: "TV"),
quantity: "1",
total: "156"),
ItemSelection(storeName: "Amazon",
productName: "Amazon Echo",
productImage: #imageLiteral(resourceName: "Amazon_Echo"),
quantity: "1",
total: "80"),
ItemSelection(storeName: "Amazon",
productName: "Grill",
productImage: #imageLiteral(resourceName: "Grill"),
quantity: "3",
total: "90"),
ItemSelection(storeName: "Amazon",
productName: "Coconut Bar",
productImage: #imageLiteral(resourceName: "coconuts"),
quantity: "4",
total: "240")
]
}()
}
Upvotes: 1
Reputation: 186
found my solution
import Foundation
struct Items {
let store: String
let productName: String
let productImage: UIImage
let quantity: String
let price: String
}
extension Items: Comparable {
static func < (lhs: Items, rhs: Items) -> Bool {
if lhs.store < rhs.store { return true }
else { return lhs.store == rhs.store && lhs.productName < rhs.productName }
}
}
extension Items {
static let retail: [Items] = [
.init(store: "Amazon",
productName: "Care Bear",
productImage: #imageLiteral(resourceName: "Bear"),
quantity: "4",
price: "156"),
.init(....
]
}
import Foundation
class ItemDataSource: NSObject {
var sections: [String: [Items]] = [:]
var items: [String] {
return sections.keys.sorted()
}
var indexes: [String] {
return items
.map { String($0.first!) }
.reduce(into: Set<String>(), { $0.insert($1) })
.sorted()
}
init(stores: [Items]) {
for store in retail.sorted(by: <) {
let items = store.items
if var stores = sections[items] {
stores.append(store)
sections[items] = stores
} else {
sections[items] = [store]
}
}
}
}
class StoreHeader: UITableViewCell {
@IBOutlet weak var dispensaryName: UILabel!
var store: String? {
didSet { storeName.text = "Store: \(store!)" }
}
}
class StoreCell: UITableViewCell {
@IBOutlet weak var productImage: UIImageView!
@IBOutlet weak var productQty: UILabel!
@IBOutlet weak var productPrice: UILabel!
@IBOutlet weak var productName: UILabel!
var product: String? {
didSet { productName.text = product }
}
var quantity: String? {
didSet { productQty.text = "Qty: \(quantity!)" }
}
var price: String? {
didSet { productPrice.text = "$\(price!)" }
}
var img: UIImage? {
didSet { productImage.image = img }
}
}
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let dataSource: ItemDataSource = .init(stores: Items.stores)
@IBOutlet weak var tableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let store = dataSource.items[section]
return dataSource.sections[store]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let storeCell = tableView.dequeueReusableCell(withIdentifier: "StoreCell") as! StoreCell
let store = dataSource.items[indexPath.section]
let storeItem = dataSource.sections[store]?[indexPath.row]
storeCell.product = storeItem?.productName
storeCell.price = storeItem?.price
storeCell.quantity = storeItem?.quantity
storeCell.img = storeItem?.productImage
return storeCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let storeHeader = tableView.dequeueReusableCell(withIdentifier: "StoreHeader") as! StoreHeader
storeHeader.store = dataSource.items[section]
return storeHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
Upvotes: 0