How do I return a boolean value? - swift

So I have a class with the method isApplicableToList(list: [ShoppingItem]) -> Bool. This should return true if a discount can be applied based on the supplied list of product ids (i.e. a product must be matched to an offer) and the product IDs are 901 and 902.
I have attempted it but uncertain if done correctly or if there is a better way.
thanks in advance!
class HalfPriceOffer :Offer {
init(){
super.init(name: "Half Price on Wine")
applicableProductIds = [901,902];
}
override func isApplicableToList(list: [ShoppingItem]) -> Bool {
//should return true if a dicount can be applied based on the supplied list of product ids (i.e. a product must be matched to an offer)
if true == 901 {
return true
}
if true == 902 {
return true
}
else {
return false
}
}
}
ShoppingItem
class ShoppingItem {
var name :String
var priceInPence :Int
var productId :Int
init(name:String, price:Int, productId:Int){
self.name = name
self.priceInPence = price
self.productId = productId
}
}

Loop through the items in your list and test if the item's productId is in the list of applicableProductIds using the contains method. If none is found, return false.
override func isApplicableToList(list: [ShoppingItem]) -> Bool {
//should return true if a dicount can be applied based on the supplied list of product ids (i.e. a product must be matched to an offer)
for item in list {
if applicableProductIds.contains(item.productId) {
return true
}
}
// didn't find one
return false
}

Related

How to check if a value in a dictionary has duplicates?

The algorithm below checks to see if an array has at least two or more duplicates. It uses a dictionary to store the occurrences; the time complexity is linear because it has to traverse the dictionary to see if a key occurs twice. In swift, how can I look up a value to see if it occurs more than twice in constant time ?
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
frequencyTable[num] = (frequencyTable[num] ?? 0 ) + 1
}
for value in frequencyTable.values{
if value >= 2 {
return true
}
}
return false
}
containsDuplicate([1,1,2,3,3,3,3,4])
The second loop is not necessary if the first loop checks if the current element has already been inserted before, and returns from the function in that case:
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
if frequencyTable[num] != nil {
return true
}
frequencyTable[num] = 1
}
return false
}
Then it becomes apparent that we don't need a dictionary, a set is sufficient:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if seen.contains(num) {
return true
}
seen.insert(num)
}
return false
}
This can be further simplified: The “insert and check if element was already present” operation can be done in a single call:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if !seen.insert(num).inserted {
return true
}
}
return false
}
This is similar to the solution from this answer
return nums.count != Set(nums).count
but possibly more efficient: The function returns immediately when a duplicate element has been detected.
Finally we can make the function generic, so that it works with all arrays of a hashable type:
func containsDuplicate<T: Hashable>(_ array: [T]) -> Bool {
var seen = Set<T>()
for element in array {
if !seen.insert(element).inserted {
return true
}
}
return false
}
Example:
print(containsDuplicate([1,1,2,3,3,3,3,4])) // true
print(containsDuplicate(["A", "X"])) // false
Or as an extension for arbitrary collections of a hashable type:
extension Collection where Element: Hashable {
func containsDuplicate() -> Bool {
var seen = Set<Element>()
for element in self {
if !seen.insert(element).inserted {
return true
}
}
return false
}
}
print([1,1,2,3,3,3,3,4].containsDuplicate())
print(["A", "X"].containsDuplicate())
You just want to know if it has duplicate, you can use use set and compare the length.
func containsDuplicate(_ nums: [Int]) -> Bool {
return Set(nums).count != nums.count
}
like this examples, because the set remove the duplicate values.

I am trying to perform search operation in swift

I have an array of managed object class named as categories
In every category, I have NSSet of apCodes
I am showing the category name in the table view section and opCodes name in table view rows.enter image description here
I want to search operation by apcodes, not by category name, but I want to show only those categories whose apcode name matches with the search text.
Here is my code, please correct my function, I unable to filter apcodes properly.
Note: I have copied the original categories array in originalCategories
func filterArray(text : String) {
categories = originalCategories
categories = categories?.compactMap { category in
guard !text.isEmpty else {
return category
}
var apCodes = [ApCode]()
if let apc = category.apCodes?.allObjects as? [ApCode] {
apCodes = apc.filter { (apcode) -> Bool in
if apcode.apCodeName?.lowercased().contains(text.lowercased()) ?? false {
return true
} else {
return false
}
}
}
if apCodes.count == 0 {
return nil
} else {
category.apCodes = NSSet(array: apCodes)
return category
}
}
if text == Constant.EMPTY_STRING {
categories = originalCategories
}
}

Equatable not detecting the difference between two objects of the same class

I have an item of the class Product. I'm changing a variable within the Product class but my addToCart method below treats the item as if no changes have been made. I'm comparing the products based on the id and the variationId. What am I doing wrong?
import UIKit
class Product: Equatable {
let id: Int
let name: String
var variationId: Int
var quantity: Int
init(id: Int, name: String, variationId: Int, quantity: Int) {
self.id = id
self.name = name
self.variationId = variationId
self.quantity = quantity
}
static func == (lhs: Product, rhs: Product) -> Bool {
return
lhs.id == rhs.id && lhs.variationId == rhs.variationId
}
}
The user can select a different color for the product and in doing so changes the variationId.
The addItemToCart() method checks if the cartItems array contains this product. If the product exists, the quantity gets increased by 1 otherwise the product is added to the array.
var cartItems = [Product]()
func addItemToCart(product: Product) {
if cartItems.contains(product) {
let quantity = product.quantity
product.quantity = quantity + 1
} else {
cartItems.append(product)
}
}
The method above keeps updating the quantity regardless if the variationId is different or not.
You are not updating the correct object. Your addItemToCart(product:) function should be something like this:
func addItemToCart(product: Product) {
if let cartItemIndex = cartItems.firstIndex(of: product) {
cartItems[cartItemIndex].quantity += product.quantity
} else {
cartItems.append(product)
}
}
You can do this as follows, you can also remove the equatable attribute.
var cartItems = [Product]()
func addItemToCart(product: Product) {
if let cardItemIndex = cardItems.firstIndex(where: { $0.id == product.id && $0.variationId == product.variationId}) {
cartItems[cardItemIndex].quantity += 1
} else {
cardItems.append(product)
}
}

how to filter data from object mapper class

i want to implement search functionality in my app but i get data from services. i have an array like this in object mapper
class Country : Mappable {
var countryName:String = ""
var countryID:Int = 0
var countryImage:String = ""
var countryColor:String = ""
required init?(_ map: Map) {
}
func mapping(map: Map) {
countryID <- map["id"]
countryName <- map["name"]
countryColor <- map["color"]
countryImage <- map["image"]
}
}
from here i want to filter my data for search functionality how to do this.
here i am filtering only country names but i want to filter whole array how i can do that
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filteredData = self.countryNames.filter { (country:String) -> Bool in
if country.lowercaseString.containsString(self.searchController.searchBar.text!.lowercaseString) {
return true
} else {
return false
}
}
print(filteredData)
// update results table view
self.resultController.tableView.reloadData()
}
You can filter your array like this way.
let filter = countries.filter { $0.countryName.lowercaseString.containsString(self.searchCon‌​troller.searchBar.te‌​xt!.lowercaseString) }
self.resultController.tableView.reloadData()

Swift: Returning a Boolean value

I am creating a sort of tilling system that will take into account offers on certain products. I need to create a half price offer that will display either true or false depending whether the offer has been applied.
HalfPrice Class:
class HalfPriceOffer :Offer {
init(){
super.init(name: "Half Price on Wine")
applicableProducts = [901,902];
}
override func isApplicableToList(list: [ShoppingItem]) -> Bool {
//should return true if a dicount can be applied based on the supplied list of products (i.e. a product must be matched to an offer)
return false
}
ShoppingItem Class
import Foundation
class ShoppingItem {
var name :String
var priceInPence :Int
var productId :Int
init(name:String, price:Int, productId:Int){
self.name = name
self.priceInPence = price
self.productId = productId
}
}
I know it uses loops; but I am unsure of how to actually write it. Thanks in advance :)
You could use the reduce function to achieve this:
func isApplicableToList(list: [ShoppingItem]) -> Bool {
return list.reduce(false) { (initial: Bool, current: ShoppingItem) -> Bool in
return initial || applicableProducts.contains(current.productId)
}
}
You can even write this shorter (Swift is awesome):
func isApplicableToList(list: [ShoppingItem]) -> Bool {
return list.reduce(false) { $0 || applicableProducts.contains($1.productId) }
}
It's perhaps less complex to think whether the offer items are in the list rather than the list items are in the offer.
override func isApplicableToList(list: [ShoppingItem]) -> Bool {
//should return true if a discount can be applied based on the supplied list of products (i.e. a product must be matched to an offer)
let a = list.map({$0.productId})
for p in applicableProducts
{
if !a.contains(p) {return false}
}
return true
}
And here's a full working code example, which fills in the implied gaps in the sample code:
class ShoppingItem {
var name: String
var priceInPence: Int
var productId: Int
init(name:String, price:Int, productId:Int){
self.name = name
self.priceInPence = price
self.productId = productId
}
}
class Offer {
var applicableProducts = [Int]()
var name:String
init(name: String) {
self.name = name
}
func isApplicableToList(list: [ShoppingItem]) -> Bool {
return false
}
}
class HalfPriceOffer: Offer {
init(){
super.init(name: "Half Price on Wine")
applicableProducts = [901,902]
}
override func isApplicableToList(list: [ShoppingItem]) -> Bool {
//should return true if a discount can be applied based on the supplied list of products (i.e. a product must be matched to an offer)
let a = list.map({$0.productId})
for p in applicableProducts
{
if !a.contains(p) {return false}
}
return true
}
}
let a = [ShoppingItem(name: "one", price: 1000, productId: 901), ShoppingItem(name: "two", price: 1009, productId: 907),ShoppingItem(name: "three", price: 1084, productId: 902)]
HalfPriceOffer().isApplicableToList(a) // true
let b = [ShoppingItem(name: "one", price: 1000, productId: 901), ShoppingItem(name: "two", price: 1009, productId: 907)]
HalfPriceOffer().isApplicableToList(b) // false