5

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 = ""
    var 
}

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.

2
  • Do you want to keep the nested hierarchy or have a flat [User] array returned? Commented Sep 20, 2016 at 13:39
  • I want to keep the nested Hierarchy that is the problem currently i am unable to solve. Commented Sep 20, 2016 at 13:44

5 Answers 5

11
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.

Sign up to request clarification or add additional context in comments.

Comments

6

A few suggestions

A struct is a better fit for a model value

struct User {
    let name: String
    let userName: String
    let email: String
    let age: Int
    let gender: String
}

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.

6 Comments

So I understand better, are you calling .filter on what's being returned from .flatMap { $0 }?
@random: with flatMap { $0 } I transform an array of arrays of User (so this [[User]]) into an array of User (this [User]).
@random: YES, the output of flatMap is processed by filter
I see. Then the filter is only returning Users that meet the criteria hints the -> Bool.
@random: By the way there was an error in my code, now it's fixed.
|
3
let textToSearch:String = "some text"

for nestedArray in myArray {

    for item:User in nestedArray
    {
        if user.name.contains(textToSearch) || user.userName.contains(textToSearch)
        {
            print("found")
        }
    }

}

3 Comments

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?
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.
Ohh.. Thank you sir. I really appreciate your help.
2

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 }

Comments

1

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!")
        }
    }

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.