Check for a certain value in a NSDictionary - ios

I am currently working on a app where i want to check if the particular object exists in the NSDictionary or not. I have tried this code but it does not seem to work. Any help will be appreciated!
for (int i=0; sizeofarray; i++) {
if ([[self.chat valueForKeyPath:#"text"] count] > 0)
{
NSDictionary* chatmessage=[self.chat objectAtIndex:i];
if ([chatmessage[#"text"] isEqualToString:#"Guest787" ]) {
NSLog(#"this happened");
}}
}
P.S sizeofarray is the length of the array and chat is the array which is stored in the dictionary.

For this task – find a dictionary with a specific key/value pair in an array – a predicate is a suitable solution.
NSString *value = #"Guest787";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"text == %#", value];
NSArray *result = [self.chat filteredArrayUsingPredicate:predicate];
BOOL valueExists = result.count > 0;
NSLog(#"%d", valueExists);
Or with Key-Value Coding (KVC)
BOOL valueExists = [[self.chat valueForKey:#"text"] containsObject:#"Guest787"];

Maybe this ?
if ([self.chat containsObject:#"Guest787"]) {
NSLog(#"this happened");
}
OR
for (NSString *message in self.chat) {
if ([message isEqualToString:#"Guest787"]) {
NSLog(#"this happened");
}
}

Related

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

How to search a value for a particular key in NSMutableArray of NSMutableDictionaries?

Hello I have a NSMutableDictionary like this
<__NSArrayM 0x14e226ff0>(
{
DocumentName = "IMG_2597.JPG";
DocumentType = JPG;
Image = "<UIImage: 0x14e52c370> size {1239, 1242} orientation 0 scale 1.000000";
}
I am adding several objects into my NSMutablearray. But I want to check whether this image already available in the NSMutablearray. Actually I am planing to search it by the DocumentName. How can I check whether that same value is already exists for the DocumentName key in the array. I want to add the NSMutableDictionary if only its not already exists. This is how I create my NSMutabledictionaryobject.
NSMutableDictionary *imageDictionary=[[NSMutableDictionary alloc] init];
[imageDictionary setObject:chosenImage forKey:#"Image"];
[imageDictionary setValue:strDocNAme forKey:#"DocumentName"];
[imageDictionary setValue:strExtension forKey:#"DocumentType"];
[mutarrayImages addObject:imageDictionary];
Please help me.
Thanks
You can try one of these to check image is already exist or not.
1) Using predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"DocumentName = 'IMG_2597.JPG'"];
NSArray *arr = [yourArray filteredArrayUsingPredicate:predicate];
if (arr.count > 0) {
NSLog(#"Object is contain");
}
2) Using valueForKey
NSArray *documentName = [yourArray valueForKey:#"DocumentName"];
if ([documentName containsObject:#"IMG_2597.JPG"]) {
NSLog(#"Object is contain");
}
NSSet* myValuesSet = [NSSet setWithArray: [mutarrayImages valueForKey:#"DocumentName"]];
if ([[myValuesSet allObjects] containsObject:< DocumentName to compare >]) {
NSLog(#"Exist");
}
else{
NSLog(#"Does not exist");
}
NSArray *allObjectsArray; // your array
NSMutableArray *resultObjectsArray = [NSMutableArray array];
for(NSDictionary *dict in allObjectsArray)
{
NSString *docName = [dict objectForKey:#"DocumentName"];
NSRange range = [docName rangeOfString:#"your string which you want to match" options:NSCaseInsensitiveSearch];
if(range.location != NSNotFound)
[resultObjectsArray addObject:dict];
}

Remove entries from NSMutableDictionary based on match on NSString value

After a network call to the Instagram API, I get back a responseDictionary NSDictionary delegate with the following Key/Value structure:
{
data = (
{
bio = "Los Angeles/Orange County Realtor\U00ae \n\U6d1b\U6749\U77f6\U623f\U5730\U4ea7\U7ecf\U7eaa\U4eba\nCall/Text/WhatsApp: (310) 717-1321\nEmail: Jxxxcom\nWeChat (\U5fae\U4fe1): xx";
"full_name" = "xx yy (\U7530\U4f73\U6dfc) Rx Realty";
id = 25354408;
"profile_picture" = "http://scontent-a.cdninstagram.com/hphotos-xpa1/outbound-distillery/t0.0-20/OBPTH/profiles/profile_xxx_75sq_1391378894.jpg";
username = jxxi;
website = "http://www.Jxghty.com";
},
The profile_picture key often has an NSString value that contains anonymousUser (for the users who didn't set any profile pictures).
I am looking to remove those entries from my responseDictionary as follows:
//Create mutable copy of IG responseDictionary
NSMutableDictionary *dictCleanAvatars = [responseDictionary mutableCopy];
NSLog(#"Log dictCleanAvatars after mutableCopy IG response: %#", dictCleanAvatars);
NSArray *keys = [dictCleanAvatars allKeys]; //get all the keys
NSUInteger k2 = [dictCleanAvatars count];
NSLog(#"k2 in dictCleanAvatars before cleanup is: %lu", (unsigned long)k2);
for (int i = 0; i<k2; i++)
{
if ([[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] isKindOfClass:[NSString class]])
{
//if its an NSString - don't want an exception if its another type of object
NSLog(#"Yes, objectAtIndex:i us Kind ofClass NSString for i = %d", i);
if ([[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] rangeOfString:#"anonymousUser"].location != NSNotFound)
{
NSLog(#"Yes, anonymousUser identified in objectAtIndex:i for i = %d", i);
//if object has the key word im looking for
[dictCleanAvatars removeObjectForKey:[keys objectAtIndex:i]]; //remove the key
NSLog(#"That's dictCleanAvatars after loop %d: %#", i, dictCleanAvatars);
}
}
}
But this doesn't work.
Would value feedback from more experience iOS developers.
If you're trying to build an array that includes everything from the data key's array, but omitting those dictionaries for which profile_picture contains the string "AnonymousUser", you can use NSPredicate:
NSArray *dataArray = responseDictionary[#"data"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"not (profile_picture contains 'AnonymousUser')"];
NSArray *filteredArray = [dataArray filteredArrayUsingPredicate:predicate];
Or you can use predicateWithBlock:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject[#"profile_picture"] rangeOfString:#"AnonymousUser"].location == NSNotFound;
}];
BTW, if you already have a mutable array, you can also remove entries from it using filterUsingPredicate, using the above predicates:
NSMutableArray *mutableDataArray = [responseDictionary[#"data"] mutableCopy];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"not (profile_picture contains 'AnonymousUser')"];
[mutableDataArray filterUsingPredicate:predicate];
If, on the other hand, you don't want to remove entire dictionaries from the array of dictionaries, but rather want to simply remove the occurrences of profile_picture for which "AnonymousUser" is present, you want to ensure that not only is the array mutable, but so are its constituent dictionaries.
The easiest way of doing this is to specify the NSJSONReadingMutableContainers option when parsing the JSON. Then you can just iterate through the NSMutableDictionary entries, removing the profile_picture entries with a profile_picture with "AnonymousUser" in them:
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSMutableArray *mutableDataArray = responseDictionary[#"data"];
for (NSMutableDictionary *dictionary in mutableDataArray) {
NSString *profilePicture = dictionary[#"profile_picture"];
if ([profilePicture rangeOfString:#"AnonymousUser"].location != NSNotFound) {
[dictionary removeObjectForKey:#"profile_picture"];
}
}
If, however, you can't specify the NSJSONReadingMutableContainers option when you parse the JSON and are stuck with a immutable collection, you need to make a mutable copy of it. Unfortunately, a simple mutableCopy of the array won't make the member dictionaries mutable themselves, but you can use a Core Foundation call to CFPropertyListCreateDeepCopy to make a mutable array with mutable entries, which you can then modify:
NSMutableArray *mutableDataArray = CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)responseDictionary[#"data"], kCFPropertyListMutableContainers));
Then you can use the above for loop, iterating through this array's dictionary entries, removing the offending profile_picture entries.
if [[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] isEqualToString#"anonymousUser"] {
The problem is, suppose [dictCleanAvatars objectForKey:[keys objectAtIndex:i]] is not an NSString? You might want to check for that first.
If the only field you are looking at is profile_picture, I would go with a less generic approach which is much more readable and understandable
This code works for me
- (void)testExample
{
NSDictionary *dictionary = #{ #"data": #[ #{ #"bio": #"blah blah", #"profile_picture": #"some stuff anonymousUser other stuff" },
#{ #"bio": #"some other object", #"profile_picture": #"some other profile picture link" }] };
// dictionary is a mock of the data you provided
NSArray *data = [dictionary objectForKey:#"data"];
for (NSDictionary * avatarDict in data) {
NSMutableDictionary *mdict = [avatarDict mutableCopy];
id ppid = [mdict objectForKey:#"profile_picture"];
if ([ppid isKindOfClass:[NSString class]]) {
NSString *pp = (NSString *)ppid;
if ([pp rangeOfString:#"anonymousUser"].location != NSNotFound) {
[mdict removeObjectForKey:#"profile_picture"];
}
}
NSLog(#"altered dictionary: %#", mdict);
}
}
Output:
2014-08-13 10:53:36.727 test[11981:60b] altered dictionary: {
bio = "blah blah";
}
2014-08-13 10:53:36.728 test[11981:60b] altered dictionary: {
bio = "some other object";
"profile_picture" = "some other profile picture link";
}

iOS: Is there a way to check if an NSArray object contains a certain character?

I need a way to know if an array has the character "#" in one of its string objects. The following code obviously doesn't work because it checks if an object just has the # sign instead of checking if an object contains the # sign. For example, if the user has test#test.com my if statement won't detect it. I need to see if a user has an email or not. I tried researching on how to accomplish this on stackoverflow, but no luck. Any tips or suggestions will be appreciated.
if([answer containsObject:#"#"]){
/// do function.
}
You can check if an NSArray contains an object with containsObject. If it's an array of characters represented as one-character strings, then the code is simple:
NSArray *array = #[#"a", #"b", #"c", #"d"];
BOOL contains = [array containsObject:#"c"];
There's no such thing as an NSArray of scalar types like 'c' char, since the NS collections contain only objects. The nearest thing to an array of chars is an NSString, which has a variety of ways to tell you if a character is present. The simplest looks like this:
NSString *string = #"test#test.com";
NSRange range = [string rangeOfString:#"c"];
BOOL contains = range.location != NSNotFound;
You have to cycle through each NSString in the array and check if it contains the substring.
This custom method shows how:
//assumes all objects in the array are NSStrings
- (BOOL)array:(NSArray *)array containsSubstring:(NSString *)substring {
BOOL containsSubstring = NO;
for (NSString *string in array) {
if ([string rangeOfString:substring].location != NSNotFound) {
containsSubstring = YES;
break;
}
}
return containsSubstring;
}
Usage:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
[array addObject:#"hi"];
[array addObject:#"yo"];
[array addObject:#"test#test.com"];
BOOL containsSubstring = [self array:array containsSubstring:#"#"];
You could create a custom Category class of NSArray and add the following method:
- (BOOL) containsCharacter:(NSString *) character
{
BOOL characterFound = NO;
for (id object in self)
{
if ([object isKindOfClass:[NSString class]])
{
NSRange range = [object rangeOfString:character];
if (range.location != NSNotFound)
{
characterFound = YES;
break;
}
}
}
return characterFound;
}
Thanks,
Michael
I think that is better way - to use predicates for filtering your array as Larme said.
Try something like this:
NSArray *answer = #[#"John Appleseed", #"john#apple.com", #"john#icloud.com", #"+14120123456", #"invalid#email", #"another###invalid.email"];
NSArray *filteredArray = [answer filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF CONTAINS \"#\""]];
if (filteredArray.count > 0) {
// Do something
}
The filteredArray will contains all objects, which contains at-symbol:
john#apple.com,
john#icloud.com,
invalid#email,
another###invalid.email
Another way - is to filter array by valid email strings and not only at-symbol:
NSArray *answer = #[#"John Appleseed", #"john#apple.com", #"john#icloud.com", #"+14120123456", #"invalid#email", #"another###invalid.email"];
NSString *emailRegex = #"[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSArray *filteredArray = [answer filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex]];
if (filteredArray.count > 0) {
// Do something
}
The filteredArray will contains only objects, which matches to email-mask
john#apple.com,
john#icloud.com

How to properly filter a NSArray using a NSPredicate

I am trying to find the tags inside a NSDictionary inside myAr that matches the criteria of str and I want the result that has only those exact arrays no more nor less. In this example I want only the 2nd NSDictionary of myAr.
I though of trying to achieve this by using a predicate but that always returns empty when i use arrays.
I am trying to filter using an array but this is not working. I was wondering if anyone could tell me what i am doing wrong and how could i achieve my objective. thanks in advance
NSArray * myAr = #[ #{ #"tags": #[#"one",#"two",#"three"],
#"number": #"4"
},
#{ #"tags": #[#"one",#"two"],
#"number":#"4"
},
#{ #"tags": #[#"one",#"two",#"four"],
#"number":#"4"
},
#{ #"tags": #[#"chacho",#"chocho"],
#"number":#"4"
},
#{ #"tags": #[#"one"],
#"number":#"4"
} ];
NSArray* str = #[#"one",#"two"];
NSPredicate* pre = [NSPredicate predicateWithFormat:#"tags CONTAINS %# ",str];
myAr = [myAr filteredArrayUsingPredicate:pre];
NSLog(#"%#",myAr);
If I understand your question correctly, you just have to replace "CONTAINS" by "="
in the predicate:
[NSPredicate predicateWithFormat:#"tags = %# ",str]
This gives an array with all dictionaries where the "tags" value is equal to the
given array str. In your example, it returns an array with the second dictionary
only.
UPDATE: To find all dictionaries where the "tags" value is an array with the
given elements, but independent of the order, the following slightly more
complicated predicate should work:
[NSPredicate predicateWithFormat:#"tags.#count = %d AND SUBQUERY(tags, $t, $t in %#).#count = %d",
[str count], str, [str count]];
UPDATE 2: That was too complicated, the following predicate seems to work as well:
[NSPredicate predicateWithFormat:#"tags.#count = %d AND ALL tags in %#",
[str count], str]
(I have assumed that str contains only different elements.)
For an answer that uses neither a for loop nor predicate format strings, try using a block and make use of NSSet to determine if the set of tags you want to match is equal to a set of the array element's tags. For example:
NSSet* desiredTags = [NSSet setWithObjects:#"one", #"two", nil];
NSPredicate *tagFilterPredicate = [NSPredicate
predicateWithBlock:^BOOL (id data, NSDictionary *bindings) {
NSSet *tags = [NSSet setWithArray:[data objectForKey:#"tags"]];
return [desiredTags isEqual:tags];
}];
NSArray *resultArray = [myArr filteredArrayUsingPredicate:tagFilterPredicate];
Bear in mind that this does allocate a set per iteration. So, if you're looking to avoid allocations, this is not adequate. Otherwise, it at least avoids a format string.
A brute-force way to do this would be to remove your predicate and just enumerate:
NSArray *required = #[#"one", #"two"];
NSMutableArray *matches = [#[] mutableCopy];
[myAr enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
BOOL match = YES;
for (NSString *item in required) {
if (![obj containsObject:item]) {
match = NO;
break;
}
}
if (match && [(NSArray *)obj count] == required.count) {
[matches addObject:obj];
}
}
}];
}];

Resources