Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a NSMutableArray which it self has many arrays inside it. Inside each array at all index they further had custom objects of class given bellow.

Class User:NSObject{
    var name = ""
    var userName = ""
    var email = ""
    var age = 0
    var gender = ""

I want to filter this nested array with respect to two objects. For example if user type some text in searchBar and check that text in that nested array if that text matches with the name or the userName or both.

let nestedArray: [[User]] = [[user1, user2], [user3], [user4, user5]]
let searchName = "foo"
let filteredArray = nestedArray.map({
        return $0.filter({ $0.name == searchName })
    }).filter({ $0.count > 0 })

This is a purely functional way that results in a new nested array that only contains arrays with matching users and these arrays also will only contain the matching users.

Don't use NSMutableArray

NSMutableArray is an Objective-C class. You can access it via Swift but you should use the Swift array struct. It is faster and, being a value type, prevents bugs related to multiple parts of your code accessing a shared object.

Filtering your data

Now given an array of arrays of User

let data: [[User]] = ...

and a keyword

let keyword: String = ...

your can filter your data writing

let matchingUsers = data
    .flatMap { $0 }
    .filter { $0.name.range(of: keyword) != nil || $0.userName.range(of: keyword) != nil }

Now matchingUsers is an array of User(s) where the name or the username contains the keyword.

So I understand better, are you calling .filter on what's being returned from .flatMap { $0 }? – random Sep 20, 2016 at 15:46 @random: with flatMap { $0 } I transform an array of arrays of User (so this [[User]]) into an array of User (this [User]). – Luca Angeletti Sep 20, 2016 at 15:48 for item:User in nestedArray if user.name.contains(textToSearch) || user.userName.contains(textToSearch) print("found") Would this method search for text at any random range inside the string?? For Example if String contains "This is Mystical String To Search" and user have just type "tica" would this method get success for searching this string in above string? – Ahsan Imtiaz Sep 20, 2016 at 13:43 yes that is correct it searches the entire string for all ranges and if it matches then returns true. So with your example it would find the text. Another example is the name was "Mark Blogs" and you searched for "log" this would find it. – torinpitchers Sep 20, 2016 at 13:45

A slightly improved version of what matteok suggested:

It makes sense to ignore register in such filtering, and instead of checking equality check if lookup target contains search query

Also using !$0.isEmpty is more swifty than checking for $0.count > 0

let nestedArray: [[User]] = [[user1, user2], [user3], [user4, user5]]
let searchName = "foo".lowercased()
let filteredArray = nestedArray
  .map { $0.filter { $0.name.lowercased().contains(searchName) }}
  .filter { !$0.isEmpty }

Here is a more "swiftly" way to go about doing this using the filter(_:) method provided by Array.

Method:

func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]

Implementation:

    // Create some generic objects to test on
    let object1 = User()
    object1.name = "John"
    object1.userName = "jdoe"
    let object2 = User()
    object2.name = "Jane"
    object2.userName = "jdoe"
    let object3 = User()
    object3.name = "Bob"
    object3.userName = "bjones"
    // Add them to a test array
    var objects = [[]]
    objects.append([object1])
    objects.append([object2])
    objects.append([object3])
    // What we want to search on
    let searchString = "j"
    // Filter the array
    for array in objects {
        let searchedSubArray = array.filter {
            return $0.name.rangeOfString(searchString, options: .CaseInsensitiveSearch)     != nil ||
                   $0.userName.rangeOfString(searchString, options: .CaseInsensitiveSearch) != nil
        if (searchedSubArray.count > 0) {
            print("we found a match!")
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.