NSPredicate String to get n'th item in array - ios

I cannot find a way to get the nth item in an array using an NSPredicate string. For example:
//You cannot touch or modify the code inside this method. You can only use the predicate string param to filter the array.
- (NSArray *)filterUsingNSPredicate:(NSString *)PredicateString
{
NSArray *array = #[
#"firstItem",
#"secondItem",
#"thirdItem",
#"fourthItem",
];
NSPredicate *pred = [NSPredicate predicateWithFormat:PredicateString];
NSArray *filtered = [array filteredArrayUsingPredicate:pred];
NSLog(#"This is the second item in the array! %#",filtered); //Thats the only thing in the array.
return filtered;
}

If you want to get an item, you don't receive an NSArray, because you will only receive an object.
You can use NSPredicate to search by name of an object in your array. But what you say, that is not what you want.
You can use [array objectAtIndex:index];, that returns the object in the position you indicate in index.
If you want the index of an object, you can use [array indexOfObject:object];, that returns the index of the object.

Predicates don't know about array indexes. They only know about the single object that they're presented with at any one time, and whether that object makes the predicate true or false.
The way you're presenting this problem in the comments makes absolutely no sense. If you can get a filtered version of the array, then you can get the array. Here's how you use the method you show to do so:
NSArray * fullList = [theAPI filterUsingNSPredicate:#"TRUEPREDICATE"];
TRUEPREDICATE is a special value for predicate strings that always evaluates to true. When you filter an array with that predicate, the result will be identical to the original.
You now have a reference to the array, and can index into it as you would normally.

You can create predicate with block https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/#//apple_ref/occ/clm/NSPredicate/predicateWithBlock%3A like this to get 6-th element (at index 5 counting from 0):
__block NSInteger index = 0;
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *, id> *bindings)(
return index++ == 5;
)];

Related

Order a pre-defined string array in order

In the following reversedArray has three or more strings such as Salads, Meats Appetizer in order.
However, I want to have Meats always to be the first string in the array.
NSPredicate *predicateMain = [NSPredicate predicateWithFormat:
#"(%K == %#)", #"categoryType", #"main"];
NSPredicate *predicateSide = [NSPredicate predicateWithFormat:
#"(%K == %#)", #"categoryType", #"side"];
NSPredicate *orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:
[NSArray arrayWithObjects:predicateMain, predicateSide,nil]];
NSArray *filteredArray = [foods filteredArrayUsingPredicate:orPredicate];
NSArray *reversedArray = [[[filteredArray valueForKeyPath:
#"#distinctUnionOfObjects.categoryName"]
reverseObjectEnumerator] allObjects];
I can do it via hardcode but I want to know proper way of handling.
To avoid hardcoding you could write a function to reorder the array with any given string as the first string, and utilize that.
For example:
void yourFunctionName(string firstString, NSArray &array){
//Iterate through array
//Check if you've found a string matching firstString
//Put it at the front by moving everything else down one
//Continue to iterate until you've reached the end of the array
}
Here it would be best to pass the array by reference (using the &) so that you modify the array itself and not just a copy of the array values (what you get when you don't pass by reference).

Extract row number of array when string searched using Predicate

I am not sure how to ask the question, so perhaps if I say what the issue is someone out there can help.
I have a SQL lite table which I use to populate two arrays: one of names and surnames, and the other array, which gets populated at the same time, of the ID of the person from the database.
I then display these names in a TableView. I use the Predicate method to search for someones name in the original array (called storiesArray).
However, when I select this person to display, it displays the First person in the stories Array.
I have tried getting the row where the search string is found, but this returns a very large number, even though it does find the string (using Predicates as explained).
How can I get the row number of the found string?
So, I have tried the following code:
NSUInteger indexOfTheObject = [storiesArray indexOfObject: searchText];
But this returns the number 2147483647, which in effect is a -1.
I know that the searchText is in stories array because the following code does return a valid search result:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", searchText];
self.searchResult = [NSMutableArray arrayWithArray:[storiesArray filteredArrayUsingPredicate:resultPredicate]];
}
self.searchResult gets populated with the correct string.
Thanks in advance.
Similar Threads here:
How retrieve an index of an NSArray using a NSPredicate?
how to find the index position of the ARRAY Where NSPredicate pick the value. I use filteredArrayUsingPredicate as filter
http://useyourloaf.com/blog/2010/10/19/searching-arrays-with-nspredicate-and-blocks.html
NSUInteger index = [self.myarray indexOfObjectPassingTest:
^(id obj, NSUInteger idx, BOOL *stop) {
return [predExists evaluateWithObject:obj];
}];

Filter an array with other array

I've got 2 arrays:
array1 contains objects of type object1. object1 has a property id.
array2 contains objects of type object2. object2 has a property object1Id.
I know, that array2 contains objects with ids which always are in array1, but array1 can have more (or equal) objects.
To show it:
So to simplify: array1 has all objects, array2 has new objects. How to get an array with old objects..? I'm trying to do it with predicate, but it feels odd to do a loop and insert each object1Id to the predicate. Is there any other option? How to do it properly?
You can use a predicate, and you don't need a loop if you use KVC.
Get the array of ids that should be excluded:
NSArray *excludeIds = [array2 valueForKey#"object1Id"];
Create the predicate:
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:#"NOT (id IN %#)", excludeIds];
Then filter:
NSArray *oldObjects = [array1 filteredArrayUsingPredicate:filterPredicate];
It looks like you are trying to perform a set operations. What can be helpful is NSMutableSet class. Use setWithArray to create sets. Then use methods like:
unionSet:
minusSet:
intersectSet:
setSet:
To get subsets that match your criteria.
Source: NSMutableSet Class Reference
Hope it helps.
NSArray* oldIds = [array2 valueForKeyPath:#"object1Id"];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"NOT (id IN %#)", oldIds];
NSArray* objects = [array1 filteredArrayUsingPredicate:predicate];

Check through an Array for a specific object

I am trying to work out how many cells my table view should have. This is determined by results of a query which are stored in Array.
When the view is loaded the array might not exist or have any values so the cells should be 0.
How do I check through my array to check for a specific object. I understand I can use containsObject or equalTo...
My array would consists of objects like this:
{<GameTurn:TLED0qH44P:(null)> {\n GameRef = \"<Game:KgguI4ig4O>\";\n GameTurnImage = \"<PFFile: 0xb3da9d0>\";\n GameTurnWord = tester;\n OriginalImageCenterX = \"27.9\";\n OriginalImageCenterY = \"29.39375\";\n TurnCount = 1;\n UploadedBy = \"<PFUser:UgkZDtDsVC>\";\n}
There would be multiple entries of the above. For each entry I need to check if the UploadedBy key is equal to the PFUser currentUser. If it is add one cell, and so on.
So I need to get an overall count of the items in the array where that key is equalto the current user.
You can filter the array to get a new array of all matching objects:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"UploadedBy = %#", currentUser];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];
and use the filtered array as table view data source.
If the array comes from a Core Data fetch request, it would be more effective to
add the predicate to the fetch request already.
There are many ways you can filter an array in Objective-C. Here is one method using blocks and NSIndexSet.
You can grab all the indexes of your original array where the objects pass a test, specified in the block. Then create another array consisting of the objects at those indexes.
// get all indexes of objects passing your test
NSIndexSet *indexes = [myArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
// replace this with your equality logic
return [obj uploadedBy] == [PFUser currentUser];
}];
// Filled with just objects passing your test
NSArray *passingObjects = [myArray objectsAtIndexes: indexes];

Code optimization (combine 2 lines of code into 1)

I have tried some combinations but can't seem to get it right. I am looking to combine line 2 and 3 into one line of code.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == 'SSM M51 Copperhead'"];
NSArray *searchResults1 = [self.weaponsArray filteredArrayUsingPredicate:predicate];
weapons = [searchResults1 objectAtIndex:0];
if(weapons.range > SSMrange)
SSMrange = weapons.range;
('weapons' is a class).
weapons = [self.weaponsArray filteredArrayUsingPredicate:predicate][0];
This isn't really going to make your code any faster though.
How about defining a method like:
- (Weapon*)firstWeaponMatchingPredicateWithFormat:(NSString*)format
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:format];
NSArray *searchResults1 = [self.weaponsArray filteredArrayUsingPredicate:predicate];
return (searchResults1.count > 0 ? [searchResults1 objectAtIndex:0] : nil);
}
Call with:
Weapon *weapon = [self firstWeaponMatchingPredicateWithFormat:#"name == 'SSM M51 Copperhead'"];
weapon = [[self.weaponsArray filteredArrayUsingPredicate:predicate] objectAtIndex:0];
There is no need to create an array object with the filtered results only to get the first object and throw away the collection.
If you're targeting iOS 4.0 or later, NSArray provides functionality to get the index of the first object passing a test through a block.
NSUInteger indexOfObject = [self.weaponsArray indexOfObjectPassingTest:^(id obj, NSUInteger index, BOOL *stop) {
return [[obj valueForKey:#"name"] isEqualToString:#"SSM M51 Copperhead"];
}];
The block will be executed once for each object and the array will stop processing when the block returns YES. Once you know the index of the object, you can get the value directly from you self.weaponsArray array. Just make sure you check the return value for NSNotFound.
I tried filtering an array of 1,000,000 objects and searching for the both the first and last object using the two approaches. Even when looking for the last object, the block approach was still quicker than using a predicate. I'm guessing due to the saving of not creating a filtered array.

Resources