4
struct User{
    var firstName:String
    var lastName:String
    var city:String
    var email:String
}

var users = [User]

I am trying to filter users as someone is typing in the textfield. Its like Search for the email. It should show all the matching results but shouldn’t duplicate the same user. I am able to filter the array based on one property such as name but not sure how to filter the array based on all the properties.

I’ve implemented the UITextField delegate and have this code for filtering.

let filteredArray = users.filter({ (user) -> Bool in
    return user.firstName.lowercased().contains(“John”)
})
6
  • 6
    Possible duplicate of Filter by multiple array conditions Commented Nov 26, 2018 at 16:08
  • 2
    Let's think about what's the meaning of the filter() closure. You iterate the array, the current element is named in your case user (that's the param). Then, according to user values, you decide to return true if you want to keep it, and false if you don't. Currently, you return true if the firstName.lowercased() contains "John". So check on the other property using an OR between them? Commented Nov 26, 2018 at 16:12
  • @Larme I never thought of using OR. You are right. Thanks Commented Nov 26, 2018 at 16:16
  • You can use AND also, it really depends on what's the reason to keep the element or not. It can be a "complicated" reason. Commented Nov 26, 2018 at 16:18
  • Use or (||) if you want to increase the number of matches. Use and (&&) if you only want to match items that meet ALL the criteria. Commented Nov 26, 2018 at 16:19

3 Answers 3

5
let filteredArray = users.filter({ $0.firstName.lowercased().contains("firstName") || $0.lastName.lowercased().contains("lastName") || ... })
Sign up to request clarification or add additional context in comments.

1 Comment

that's a very long line. It's better to split it up.
2

You can set multiple conditions and combine them together with OR (||) or AND (&&)- its a simple boolean, you can think of it as it was in an if statement-

if user.firstName.lowercased().contains("john") || user.lastName.lowerCased().contains("lastname") { return true }
else { return false }

so in your code it will be like

let filteredArray = users.filter { (user) -> Bool in
return user.firstName.lowercased().contains("john") || user.lastName.lowercased().contains("lastname") }

6 Comments

don't do if b { return true } else { return false }. Just do return b.
It doesn't clarify anything. It just adds irrelevant redundancy
It does because this syntax might be confusing for starting programmers, so I converted it to a simple if statement. A lot of starters have problems understanding that if statement is actually consist from a boolean
From that perspective (of the absolute beginner), your code is strictly more complex. It requires understanding booleans, if statements and return statements, whereas my suggested code only requires understanding return statements.
beginners don't consider "user.firstName.lowercased().contains("john") || user.lastName.lowerCased().contains("lastname")" as a single boolean parameter "b"
|
2

Since you'll probably need to search multiple things, I would recommend you make a Searchable protocol, and make aggregate types searchable by virtue of checking if any of their constituents match.

import Foundation

struct User {
    let firstName: String
    let lastName: String
    let city: String
    let email: String
    let age: Int // an example of a non-String type.
}

protocol Searchable {
    func matches(query: String) -> Bool 
}

extension String: Searchable {
    func matches(query: String) -> Bool {
        // Implement any kind of searching algorithm here. Could be as smart as fuzzy seraching
        // or as basic as this case-insenitive simple substring search
        return self.lowercased().contains(query)
    }
}

extension Int: Searchable {
    func matches(query: String) -> Bool {
        return String(self).matches(query: query)
    }
}


extension User: Searchable {
    func matches(query: String) -> Bool {
        let constituents: [Searchable] = [firstName, lastName, city, email, age]
        return constituents.contains(where: { $0.matches(query: query) })
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.