简体   繁体   中英

Using NSPredicate in 2D Arrays

This question is based off of the same app/source from my previous question which can be found here:

How to manage memory using classes in Objective-C?

I have a nested array which looks something like this when printed out (I only copied and pasted a brief part of it).

(
        (
        <Term: 0x4256420>,
        <Term: 0x420fa40>,
        <Term: 0x4257bd0>,
        <Term: 0x4257cf0>,
        <Term: 0x4257d90>,
        <Term: 0x4257e30>
    ),
        (
        <Term: 0x4257e50>,
        <Term: 0x4257f90>,
        <Term: 0x4257fb0>,
        <Term: 0x42580e0>,
        <Term: 0x4258170>,
        <Term: 0x4258210>,
        <Term: 0x4258230>,
        <Term: 0x4258360>,
        <Term: 0x4258400>,
        <Term: 0x42584a0>,
        <Term: 0x4258540>,
        <Term: 0x42585e0>,
        <Term: 0x4258670>,
        <Term: 0x4258710>
    ),

And here is my code for the search part of my table:

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section 
{
    // Normal table
    if (aTableView == self.tableView) return [[self.sectionArray objectAtIndex:section] count];

    // Search table
    //NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name contains[cd] %@", self.searchBar.text];
    //self.filteredArray = [self.crayonColors filteredArrayUsingPredicate:predicate];
 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name contains[cd] %@", self.searchBar.text];
    self.filteredArray = [[self.sectionArray objectAtIndex:section] filteredArrayUsingPredicate:predicate];


    return self.filteredArray.count;
}

I am getting the error that I cannot allocate enough room which means that I must be doing something wrong, I just cannot figure out what.

The commented out portion of the search part in the above method works but crayonColors is just a simple NSMutableDictionary of NSStrings and does not have arrays nested inside of it.

Thanks in advance!

As far as I'm aware, you can't do this with a single predicate. However, you can do it with a key-path operator and a predicate in two separate calls.

So, you have an array of arrays of terms. You want a single array of terms where its name contains 'A' (for example). Here's what you do:

NSArray * allTerms = ...; //your array of arrays of terms
NSArray * collapsedTerms = [allTerms valueForKeyPath:@"@unionOfArrays.self"];

NSPredicate * filter = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", @"A"];
NSArray * filteredTerms = [collapsedTerms filteredArrayUsingPredicate:filter];

The magic here is the valueForKeyPath: bit. The @unionOfArrays operator takes an array of arrays of objects, and returns an array of objects. Here's what it's doing: The NSArray is going to break the keypath up by . , giving it @unionOfArrays and self . It's going to recurse and invoke valueForKeyPath: on itself using the second bit (self), and it's going to get back an array of arrays. It's then going to mash all those arrays together into a single array, ignoring duplicates. (If you want to remove duplicates, use @distinctUnionOfArrays instead)

Once we have that array of objects, we can then filter it normally using a simple name CONTAINS 'blah' predicate.

(I thought I might be able to get this to work using a SUBQUERY , but that's a strange beast and nothing was immediately obvious to me.)

For the super intrepid, you could do this with a single method call using KickingBear's collection extensions ( available here ), but I would strongly advise against using hacks like that in a production setting. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM