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
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"]];
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
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;
}
}
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];
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;
}
}