Need assistance regarding NSPredicate - ios

I have an NSMutableArray which contains several NSMutableDictonaryobjects. I am using NSPredicate to find out that dictionary with specific key exist or not in the array
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%# IN self.#allKeys", users.cellNum];
NSArray *predResult = [[[self appDelegate]mainArray] filteredArrayUsingPredicate:pred];
BOOL success = predResult.count == 0;
if(success) {
}
its working fine but in predResult I am getting the whole object and it will become memory overhead as the size grows with time.
So I just want to know the dictionary with specific key exist in array or not. I don't want to fetch any object using filteredArrayUsingPredicate.

NSUInteger rowindex = [[[self appDelegate]mainArray] indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [pred evaluateWithObject:obj];
}];
This will return the integer and
if(rowindex==0|| (rowindex>0&&rowindex<[[self appDelegate]mainArray].count)) {
// data found
}
If data is found rowindex will be greater than zero and less than array count

Related

Convert NSArray to specific object type without loop [duplicate]

How to search an NSSet or NSArray for an object which has an specific value for an specific property?
Example: I have an NSSet with 20 objects, and every object has an type property. I want to get the first object which has [theObject.type isEqualToString:#"standard"].
I remember that it was possible to use predicates somehow for this kind of stuff, right?
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"type == %#", #"standard"];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];
id firstFoundObject = nil;
firstFoundObject = filteredArray.count > 0 ? filteredArray.firstObject : nil;
NB: The notion of the first found object in an NSSet makes no sense since the order of the objects in a set is undefined.
You can get the filtered array as Jason and Ole have described, but since you just want one object, I'd use - indexOfObjectPassingTest: (if it's in an array) or -objectPassingTest: (if it's in a set) and avoid creating the second array.
Generally, I use indexOfObjectPassingTest: as I find it more convenient to express my test in Objective-C code rather than NSPredicate syntax. Here's a simple example (imagine that integerValue was actually a property):
NSArray *array = #[#0,#1,#2,#3];
NSUInteger indexOfTwo = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return ([(NSNumber *)obj integerValue] == 2);
}];
NSUInteger indexOfFour = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return ([(NSNumber *)obj integerValue] == 4);
}];
BOOL hasTwo = (indexOfTwo != NSNotFound);
BOOL hasFour = (indexOfFour != NSNotFound);
NSLog(#"hasTwo: %# (index was %d)", hasTwo ? #"YES" : #"NO", indexOfTwo);
NSLog(#"hasFour: %# (index was %d)", hasFour ? #"YES" : #"NO", indexOfFour);
The output of this code is:
hasTwo: YES (index was 2)
hasFour: NO (index was 2147483647)
NSArray* results = [theFullArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF.type LIKE[cd] %#", #"standard"]];

How get objects from one array with same properties of other?

For example:
I have two NSMutableArray. One #[1,2,3,4,5,6,7]. Other have objects like
#[
#{#idObjectToSearch":1, #"name":#"aaaaa", #"surname": #"bbbbb"}, #{#idObjectToSearch":2, #"name":#"aaaaa", #"surname": #"ccccc"},
...
#{#idObjectToSearch":100, #"name":#"aaaaa", #"surname": #"cccdcd"}
];
So how I could extract needed objects from second array more effective way?
You need to use NSPredicate with your second array.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"idObjectToSearch IN %#", firstArray];
//In above predicate instead of passing `1` you need to pass object from first array that you want.
NSArray *filterArray = [secondArray filteredArrayUsingPredicate:predicate];
//Now access Array objects
if (filterArray.count > 0) {
NSLog(#"%#",filterArray);
}
You can do it like this
NSMutableArray * arrSorted = [NSMutableArray new];
for(int i=0;i<arr.count;i++) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"idObjectToSearch == %#", firstArray[i]];
NSUInteger index = [secondArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [predicate evaluateWithObject:obj];
}];
if (index != NSNotFound) {
[arrSorted addObject:[arrM objectAtIndex:index]];
}
}
arrSorted will contain your sorted data

Find index of value which is stored into NSDictionary and NSDictionary stored into NSMutableArray

I have NSMutableArray which stores NSDictionary. Consider following array which contain NSDictionary.
<__NSArrayM 0x7f9614847e60>(
{
"PARAMETER_KEY" = 1;
"PARAMETER_VALUE" = ALL;
},
{
"PARAMETER_KEY" = 2;
"PARAMETER_VALUE" = ABC;
},
{
"PARAMETER_KEY" = 3;
"PARAMETER_VALUE" = DEF;
},
{
"PARAMETER_KEY" = 4;
"PARAMETER_VALUE" = GHI;
},
{
"PARAMETER_KEY" = 5;
"PARAMETER_VALUE" = JKL;
}
)
I can find index of specific NSDictionary using following code.
int tag = (int)[listArray indexOfObject:dictionary];
But If I have PARAMETER_VALUE = GHI and using this value I want to find that dictionary index into array. I don't want to use for loop. Can I get index without for loop?
You can use indexOfObjectPassingTest method of NSArray:
[listArray indexOfObjectPassingTest:^BOOL(NSDictionary* _Nonnull dic, NSUInteger idx, BOOL * _Nonnull stop) {
return [dic[#"PARAMETER_VALUE"] isEqualToString:#"GHI"];
}];
Also, please consider using indexesOfObjectsPassingTest if you can have multiple dictionaries with the same PARAMETER_VALUE
You can add a category on NSArray like this (this does a type safety check as well; only array of dictionaries are processed):
- (NSInteger)indexOfDictionaryWithKey:(NSString *)iKey andValue:(id)iValue {
NSUInteger index = [self indexOfObjectPassingTest:^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
if (![dict isKindOfClass:[NSDictionary class]]) {
*stop = YES;
return false;
}
return [dict[iKey] isEqual:iValue];
}];
return index;
}
And then simply call indexOfDictionaryWithKey:andValue: directly on your array object to get the index.
Just in case if you want to get the dictionary object out of that array, add one more category in NSArray:
- (NSDictionary *)dictionaryWithKey:(NSString *)iKey andValue:(id)iValue {
NSUInteger index = [self indexOfDictionaryWithKey:iKey andValue:iValue];
return (index == NSNotFound) ? nil : self[index];
}
You can use NSPredicate for this purpose:
// Creating predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.PARAMETER_VALUE MATCHES %#",#"GHI"];
// Filtering array
NSArray *filteredArr = [arr filteredArrayUsingPredicate:predicate];
// If filtered array count is greater than zero (that means specified object is available in the array), checking the index of object
// There can be multiple objects available in the filtered array based on the value it holds (In this sample code, only checking the index of first object
if ([filteredArr count])
{
NSLog(#"Index %d",[arr indexOfObject:filteredArr[0]]);
}
Well, one has to enumerate in a way. Taking your requirement literally (no for loop), you can use fast enumeration. However, the task can be run concurrently, because you only need read access:
__block NSUInteger index;
[array enumerateObjectsWithOptions: NSEnumerationConcurrent
usingBlock:
^(NSDictionary *obj, NSUInteger idx, BOOL *stop)
{
if( [obj valueForKey:#"PARAMETER_VALUE" isEqualToString:#"GHI" )
{
index = idx;
*stop=YES;
}
}

Filtering an array with a predicate, limit results?

I am filtering an array that can have many objects with a predicate. I would like to limit the results returned for performance reasons. The array is not sorted, so once the limit is hit, I would like the search to stop.
Is this possible? I am not sure if by means of predicate directive or otherwise.
I think you can use this combination of indexesOfObjectsPassingTest and objectsAtIndexes:
NSUInteger count = 0;
NSUInteger limit = ...;
NSIndexSet *set = [myArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
BOOL pass = ... // check if object passes test;
if (pass) {
count++;
if (count >= limit)
*stop = YES; // stops further processing of the array
}
return pass;
}];
NSArray *filteredArray = [myArray objectsAtIndexes:set];

NSPredicate check NSArray if object has one of several ID

Little diifficult to explain but I am trying to use NSPredicate for filtering an array with custom NSManagedObject by ids. I have a server that can send update, delete or add new objects, and I need to control if those objects from the JSON file already exist, if exist just update them or insert to core data if not.
I am using this predicate now :
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"storeId != %#", [jsonFile valueForKey:#"Id"];
Where jsonFile contains unparsed Store objects. But with this predicate, it will give me a huge array, since one id will be unlike some storeId, and next id will match.
Json file is some sort of this :
"Stores":[{
"id":1,
"name":"Spar",
"city":"London"
}
{
"id":2,
"name":"WalMart",
"city":"Chicago"
}];
I am not sure if I understand correctly what you are trying to achieve, but perhaps you can use the following:
NSArray *jsonFile = /* your array of dictionaries */;
NSArray *idList = [jsonFile valueForKey:#"id"]; // array of "id" numbers
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT(storeId IN %#)", idList];
This will give all managed objects that have a storeId that is not equal to any of the ids in the jsonFile array.
The syntax of the predicate is probably off - someone else may suggest a fix - but if you have an array, why not use
- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
since its much easier:
NSInteger textID = ... // you set this
NSInteger idx = [myArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop))
{
NSInteger objIdx = [obj objectForKey:#"id"] integerValue]; // integerValue works for both NSNUmbers and NSStrings
if(objIdx == testID) {
return YES;
*stop = YES;
}
}

Resources