Filter Array of Custom Objects in Swift

Filtering array of custom objects

From what I can see from your question, none of the above really has any connection to Objective-C. Your example contains a few other issues, however, keeping it from working as intended.

  • MyObject has no initializer (as of Swift 2.2, you should include at least one initializer).
  • What are obj1, obj2, ... ? You treat these as methods or class/structures types, when I presume you're intending for these to be instances of the MyObject type.

If fixing the above, the actual filtering part of your code will work as intended (note that you can omit () from filter() {... }), e.g.:

enum ObjectType{
case type1
case type2
case type3
}

class MyObject {
var type : ObjectType
let id: Int
init(type: ObjectType, id: Int) {
self.type = type
self.id = id
}
}

let array = [MyObject(type: .type1, id: 1),
MyObject(type: .type2, id: 2),
MyObject(type: .type3, id: 3),
MyObject(type: .type2, id: 4),
MyObject(type: .type3, id: 5)]

let type2Array = array.filter { $0.type == .type2}
type2Array.forEach { print($0.id) } // 2, 4

As an alternative to filtering directly to an enumeration case, you could specify the rawValue type of your enumeration and match to this instead. E.g. using an Int rawValue allows you to (in addition to filtering w.r.t. rawValue) perform pattern matching for say, ranges of cases in your enumeration.

enum ObjectType : Int {
case type1 = 1 // rawValue = 1
case type2 // rawValue = 2, implicitly
case type3 // ...
}

class MyObject {
var type : ObjectType
let id: Int
init(type: ObjectType, id: Int) {
self.type = type
self.id = id
}
}

let array = [MyObject(type: .type1, id: 1),
MyObject(type: .type2, id: 2),
MyObject(type: .type3, id: 3),
MyObject(type: .type2, id: 4),
MyObject(type: .type3, id: 5)]

/* filter w.r.t. to rawValue */
let type2Array = array.filter { $0.type.rawValue == 2}
type2Array.forEach { print($0.id) } // 2, 4

/* filter using pattern matching, for rawValues in range [1,2],
<=> filter true for cases .type1 and .type2 */
let type1or2Array = array.filter { 1...2 ~= $0.type.rawValue }
type1or2Array.forEach { print($0.id) } // 1, 2, 4

How do I filter on an array of objects in Swift?

So I quickly did this to help out, if someone can improve that's fine I'm just trying to help.

I made a struct for the books

struct Book {
let title: String
let tag: [String]
}

Created an array of those

var books: [Book] = []

Which is empty.

I created a new object for each book and appended to books

let dv = Book(title: "The Da Vinci Code", tag: ["Religion","Mystery", "Europe"])
books.append(dv)
let gdt = Book(title: "The Girl With the Dragon Tatoo", tag: ["Psychology","Mystery", "Thriller"])
books.append(gdt)
let fn = Book(title: "Freakonomics", tag: ["Economics","non-fiction", "Psychology"])
books.append(fn)

So you've three objects in the books array now.
Try to check with

print (books.count)

Now you want to filter for Psychology books.
I filtered the array for tags of Psychology - are filters ok for you?

let filtered = books.filter{ $0.tag.contains("Psychology") } 
filtered.forEach { print($0) }

Which prints the objects with your two Psychology books

Book(title: "The Girl With the Dragon Tatoo", tag: ["Psychology",
"Mystery", "Thriller"])

Book(title: "Freakonomics", tag: ["Economics", "non-fiction",
"Psychology"])

Filter Nested Array of Custom Object in Swift

I believe it is possible to achieve your goal using your approach and simply adapting your filter logic.

Try creating a method to filter your array of SectionIndex instances:

let array: [SectionIndex] = []

The method loops through each section and filters the rows the same way you did. After that, simply verify if any row matched the search and if it did, create a new SectionIndex copy adding only the rows that matched the search.

func filterSections(with searchText: String) -> [SectionIndex] {
var searchedData: [SectionIndex] = []

for sectionIndex in array {
let filteredRows: [RowIndex] = sectionIndex.data.filter({
$0.reg?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
|| $0.type?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
|| $0.type?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
|| $0.reg?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
})

// Ignore the section if not rows match the search
if filteredRows.isEmpty { continue }

let newSectionIndex = SectionIndex(
index: sectionIndex.index!, // TODO: handle the optional value
title: sectionIndex.title!, // TODO: handle the optional value
date: sectionIndex.date!, // TODO: handle the optional value
data: filteredRows,
minutes: sectionIndex.minutes! // TODO: handle the optional value
)

searchedData.append(newSectionIndex)
}

return searchedData
}

Finally on the search callback:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
if searchText != ""
{
searchedData = filterSections(with: searchText)
searching = true
table1.reloadData()
}
else
{
searching = false
table1.reloadData()
}
}

The tableView data source methods would look like something like this:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchedData[section].data.count
} else {
return array[section].data.count
}
}

func numberOfSections(in tableView: UITableView) -> Int {
if searching {
return searchedData.count
} else {
return array.count
}
}

Filter array of custom objects with an attribute and Map in Swift

for (index, job) in idsJobModel.enumerated() {
if let match = arrFiltetered.first( where: {job.id == $0.id} ) {
idsJobModel[index] = match
}
}

Or if you prefer using map:

idsJobModel = idsJobModel.map {
let myID = $0.id
if let match = arrFiltetered.first( where: {myID == $0.id} ) {
return match
} else {
return $0
}
}

Either version of the code above will have O(n²) performance, so it will get dramatically slower as your arrays get larger than ≈30 elements. It would need to be tweaked to perform well on larger arrays.

How Filter Custom Object Array with Condition

let result = secondArray
result.append(contentsOf: fisrtArray.filter { item in
!secondArray.contains(where: { $0.id == item.id })
})

After that you can sort the result by id

Swift: Get indices of an array of objects filtered by a certain property

You could filter the indices

let selectedIndices = myObjects.indices.filter{selectedIds.contains(myObjects[$0].ID)}

Filter array of custom objects in Swift

In Swift 1.2, filter is a global function, so you can't say dataPool.filter(...). (In Swift 2, this will work.)

Furthermore, contains can't be used with Strings like that. I would recommend using the rangeOfString: method from NSString:

let teachers = filter(dataPool) { // in Swift 2 this would be "dataPool.filter {"
return $0.position!.rangeOfString("TEACHER") != nil
}

How to filter array of items by another array of items in swift

Chose 1 in 2 option of return:

     func filter(items: [Item], contains tags: [String]) -> [Item] {
items.filter { (item) -> Bool in
let tagNames = item.tags.map({ $0.name })
return tags.allSatisfy(tagNames.contains)
return Set(tags).isSubset(of: Set(tagNames))
}
}


Related Topics



Leave a reply



Submit