0

I've added a search bar that successfully searches through the menu names. However, the menu price does not filter at all, and I don't know how to control the two arrays in a way that when I search and get a result of menu["a" , "c"], the price array displays the prices that are correspondant to the menu array; price["Price of a", "Price of c"]. The list displays three objects; image of the menu, name of the menu, and the price.

var menu = ["Ice Tea (Large)", "Ice Tea (Small)", "Green Apple Refresher (Large)","Green Apple Refresher (Small)", "Peach Refresher (Large)", "Peach Refresher (Small)"]
var price = ["Rs.80", "Rs.50", "Rs.110", "Rs.80", "Rs.110", "Rs.80"]
var currentMenuNameArray = [String]()
class myMenu: UITableViewController, UISearchBarDelegate
{

@IBOutlet weak var tdMenuSearchBar: UISearchBar!

override func viewDidLoad()
{
    super.viewDidLoad()
    tdMenuSearchBar.delegate = self
    currentMenuNameArray = menu
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return currentMenuNameArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as!TigersDenTableViewCell

    cell.tdMenuImage.image = UIImage(named:currentMenuNameArray[indexPath.row] + ".jpg")
    cell.tdMenuName.text = currentMenuNameArray[indexPath.row]
    cell.tdMenuPrice.text = price[indexPath.row]

    return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
    return 100
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
    guard !searchText.isEmpty else {
        currentMenuNameArray = menu
        tableView.reloadData()
        return
    }
    currentMenuNameArray = menu.filter( { (menu:String) -> Bool in        menu.lowercased().contains(searchText.lowercased())
    })
    tableView.reloadData()
}
}

3 Answers3

1

You can zip (because you mentioned that the price array displays the prices that are correspondent to the menu array) two arrays, filter by menu values and get two filtered arrays.

let searchString = "Green"

let menu = ["Ice Tea (Large)", "Ice Tea (Small)", "Green Apple Refresher (Large)","Green Apple Refresher (Small)", "Peach Refresher (Large)", "Peach Refresher (Small)"]
let price = ["Rs.80", "Rs.50", "Rs.110", "Rs.80", "Rs.110", "Rs.80"]

let result = zip(menu, price).filter { menuItem, _ in
    menuItem.lowercased().contains(searchString.lowercased())
}

print(result) // array of tuples [("Green Apple Refresher (Large)", "Rs.110"), ("Green Apple Refresher (Small)", "Rs.80")]

let filteredMenu = result.map({ $0.0 })
let filteredPrice = result.map({ $0.1 })

print(filteredMenu, filteredPrice) // two separate arrays ["Green Apple Refresher (Large)", "Green Apple Refresher (Small)"] ["Rs.110", "Rs.80"]
pacification
  • 5,838
  • 4
  • 29
  • 51
1
var menu = ["Ice Tea (Large)", "Ice Tea (Small)", "Green Apple Refresher (Large)","Green Apple Refresher (Small)", "Peach Refresher (Large)", "Peach Refresher (Small)"]
var price = ["Rs.80", "Rs.50", "Rs.110", "Rs.80", "Rs.110", "Rs.80"]

The issue is that menu and price are sync'ed. Meaning that if you remove one item from menu, you need to remove the corresponding one (same index) in price. But keeping them manually sync'ed is adding work to do, while using a single array for them is enough and makes more sense.

Quick solution: Use an array of Dictionaries:

var menu:[[String:String]] = ["Name":"Ice Tea (Large)", "Price":"Rs.80",
                              "Name":"Ice Tea (Small)", "Price":"Rs.50",
                              ...]

Then:

cell.tdMenuImage.image = UIImage(named:currentArray[indexPath.row]["Name"] + ".jpg")
cell.tdMenuName.text = currentArray[indexPath.row]["Name"]
cell.tdMenuPrice.text = currentArray[indexPath.row]["Price"]

And:

currentMenuNameArray = menu.filter( { (menu:[String:String]) -> Bool in   
    menu["Name"].lowercased().contains(searchText.lowercased())
})

I don't know the scope of your code, but I'd suggest to create your own object/struct, with a String Property name, a Double property price, maybe a property from a custom enum to define if it's large or small.

It's not beautiful Swift code, but it's more to explain the logic, and what could give you the benefits of using custom objects:

import UIKit

enum MenuSize: String {
    case small = "Small"
    case large = "Large"
}

class Menu: NSObject {
    let name: String
    let price: Double
    let size: MenuSize

    required init(withName name: String, withPrice price: Double, andSize size: MenuSize) {
        self.name = name
        self.price = price
        self.size = size
    }

    func displayableName() -> String {
        return name + " (" + self.size.rawValue + ")"
    }

    func imageName() -> String {
        return self.name + ".jpg"
    }
}

Sample code to test:

let menu1 = Menu.init(withName: "Ice tea", withPrice: 0.80, andSize: .large)
let menu1Name = menu1.displayableName()
print("menu1Name: \(menu1Name)")

let menu2 = Menu.init(withName: "Ice tea", withPrice: 0.50, andSize: .small)
let menu3 = Menu.init(withName: "Diet Coke", withPrice: 0.50, andSize: .small)
let menu4 = Menu.init(withName: "Diet Coke", withPrice: 1.00, andSize: .large)

let array = [menu1, menu2, menu3, menu4]

let filtered = array.filter { (menuToTest:Menu) -> Bool in
    return menuToTest.name.lowercased().contains("et".lowercased())
}

You could use a NumberFormatter to display the price with Rupees. (Related SO question).

The code in tableView(_ tableView:cellForRowAt:) is then:

let currentMenu = currentArray[indexPath.row]
cell.tdMenuImage.image = UIImage(named: currentMenu.imageName())
cell.tdMenuName.text = currentMenu.displayableName()
cell.tdMenuPrice.text = //Use the formatter
Larme
  • 24,190
  • 6
  • 51
  • 81
0

Adding to @pacification's answer, to also filter price array.. try following

let searchString = "5"

let menu = ["Ice Tea (Large)", "Ice Tea (Small)", "Green Apple Refresher (Large)","Green Apple Refresher (Small)", "Peach Refresher (Large)", "Peach Refresher (Small)"]
let price = ["Rs.80", "Rs.50", "Rs.110", "Rs.80", "Rs.110", "Rs.80"]

    let result = zip(menu, price).filter { menuItem, priceItem in
        menuItem.lowercased().contains(searchString.lowercased()) ||
        priceItem.lowercased().replacingOccurrences(of: "rs.", with: "").contains(searchString.lowercased())
    }


print(result) // array of tuple [("Ice Tea (Small)", "Rs.50")]

let filteredMenu = result.map({ $0.0 }) let filteredPrice = result.map({ $0.1 })

print(filteredMenu, filteredPrice) // two separate array ["Ice Tea (Small)"] ["Rs.50"]
Aju Antony
  • 639
  • 6
  • 13