1

I am having a problem that I can't find a good answer to by myself.

I have an array containing objects that contain information about companies. Based on this objects I create a collection view where I populate the items from the information inside those objects.

var suppliers = [Suppliers]()

Now I want to add buttons with specific filters. When pressed on one or more of those buttons the collection view should update with the filters applied.

Therefore I made a few buttons and when pressed I add them to an array containing all the filters.

var filters = [Category]()

After that I call a method that should do the filtering and update the collection view.

private func filter()
{
    if filters.count > 0 {
        suppliers.filter({ ($0.category!).contains(filters)})
    }
}

Unfortunately I can't comparison like that, according to xCode. How do I achieve this filtering correctly?

edit: See the structure of the object below.

struct Supplier : JSONJoy {

    var about: String?
    var category: Array<Category>?
    var logo: String?
    var name: String?

    init(_ decoder: JSONDecoder) {
        name = decoder["name"].string
        logo = decoder["logo"].string
        about = decoder["about"].string
        if let ctgrys = decoder["category"].array {
            category = Array<Category>()
            for ctgryDecoder in ctgrys {
                category?.append(Category(ctgryDecoder))
            }
        }
}

struct Category : JSONJoy {
    var id: Int?
    var name: String?

    init(_ decoder: JSONDecoder) {
        id = decoder["id"].integer
        name = decoder["name"].string
    }

}
Luca D'Alberti
  • 4,749
  • 3
  • 25
  • 45
Reshad
  • 2,570
  • 8
  • 45
  • 86
  • does your array contain 'custom object'? show the structure of data. – Bista Dec 30 '15 at 11:36
  • I added the custom objects structures @the_UB – Reshad Dec 30 '15 at 11:45
  • [check this](http://stackoverflow.com/questions/32039714/filter-array-of-custom-objects-in-swift) & [this](http://stackoverflow.com/questions/27709723/filter-array-of-anyobject-in-swift) – Bista Dec 30 '15 at 12:03
  • How do you want to filter the suppliers? Do you want the `suppliers` with at **least one filter** listed in `filters`? Or all the supplier having **all the filters** listed in `filters`? – Luca Angeletti Dec 30 '15 at 15:55

3 Answers3

1

1) $0.category! is [Category] type. And you have [Category].contains call which requires (Category) throws -> Bool parameter, but in your case it is filters variable with [Category] type

2) You never apply your filter result

This is possible implementation of your filtering, if I understand your needs correctly:

private func filter() -> [Supplier] {
    if filters.count > 0 {
        return suppliers.filter { supplier in
            return supplier.category?.contains { supplierCategory in
                return filters.contains {
                    return supplierCategory.id == $0.id
                }
            } ?? false
        }
    } else {
        return suppliers
    }
}
Silmaril
  • 4,241
  • 20
  • 22
1

We need to fix a couple of details that are going to make our lifes easier :)

1. Category becomes Equatable and Hashable

struct Category: JSONJoy, Equatable, Hashable {
    var id: Int?
    var name: String?

    init(_ decoder: JSONDecoder) {
        id = decoder["id"].integer
        name = decoder["name"].string
    }
    var hashValue: Int { get { return id?.hashValue ?? 0 } }
}

func ==(left:Category, right:Category) -> Bool {
    return left.id == right.id && left.name == right.name
}

2. Supplier does not like an optional category property

struct Supplier: JSONJoy {

    var about: String?
    var category = [Category]() // <- I changed this
    var logo: String?
    var name: String?

    init(_ decoder: JSONDecoder) {
        name = decoder["name"].string
        logo = decoder["logo"].string
        about = decoder["about"].string
        if let ctgrys = decoder["category"].array {
            category = Array<Category>()
            for ctgryDecoder in ctgrys {
                category.append(Category(ctgryDecoder))
            }
        }
    }
}

3. Now let't filter them all

You have your list of suppliers and your list of filters

var suppliers = [Supplier]()
var filters = [Category]()

Now I am not sure about how you want to filter suppliers.

However IF you want all the suppliers having at least a filter listed in filters then

let requiredFilters = Set(filters)
let supplierWithAtLeastOneRequiredFilter = suppliers.filter { !Set($0.category).intersect(requiredFilters).isEmpty }

On the other hand IF you want all the suppliers having all the filters listed in filters then

let requiredFilters = Set(filters)
let supplierWithEveryRequiredFilter = suppliers.filter { Set($0.category).isSupersetOf(filters) }
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
0

Assuming filtered is the filtered array of Supplier. and AllData is the full array of Supplier. And you want to filter only items which contain the word "ao" at their name property.

  filtered  = AllData.filter {
                $0.name.rangeOfString("ao", options: .CaseInsensitiveSearch) != nil
            }
        if(filtered.count == 0){
           //No Results - 
        } else {
              //There are results - update the tableView data source accordingly
        }
Roi Mulia
  • 5,626
  • 11
  • 54
  • 105