I have a NSDictionary object with 2 items, the first one is a NSString and the second is an Integer. When I loop into the dictionary items I'd like detect what of they is an Integer.
What is the best way to do it?
The current dictionary is:
[[NSDictionary alloc] initWithObjectsAndKeys:#"San", #"name", #"123", #"id", nil]
The item you are putting in the dictionary is in no way an integer, it's a NSString which only contains numbers. Why not just use a NSNumber object and use it the way it should be?
[[NSDictionary alloc] initWithObjectsAndKeys:#"San", #"name", #123, #"id", nil]
This uses a literal for a NSNumber.
You can use isKindOfClass: to check if an object is of a specific class and enumerateKeysAndObjectsUsingBlock: to analyze every object contained in a dictionary.
For example:
NSDictionary *dictionary = #{#"name": #"San", #"id": #123};
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSNumber class]])
NSLog(#"%#: %# is a number", key, obj);
else
NSLog(#"%#: %# is NOT a number", key, obj);
}];
The first line is a NSDictionary creation using literals, the same is for #123, which automatically insert a NSNumber with 123 value in the dictionary.
Related
So I have an object of type 'id friendData'stored in a singleton class 'coreData' from which I produce a mutable array for object key "data" as follows:
NSMutableArray *friends = [_coreData.friendData objectForKey:#"data"];
I then establish a dictionary which takes user parameters using keys "id" and "name", as well as a NSMutable array *scores which is obtained by a HTTP post request.
NSMutableDictionary *directory = [NSMutableDictionary dictionary];
[directory setObject:[friends valueForKey:#"id"] forKey:#"id"];
[directory setObject:[friends valueForKey:#"name"] forKey:#"name"];
[directory setObject:scores forKey:#"score"];
I am wanting to order object scores from highest to lowest for the purposes of a scoreboard, but it's my understanding that rearranging within a dictionary won't maintain the same order for the objects 'id' and 'name'. Is this infact possible, or is it better to reintroduce the *scores object to *friends under an appropriate key, and apply a sort algorith? If so, how? Any help, including example code and possible sort procedure would be great!
Just sort scores array before setting it into the dictionary. I am not sure what are exactly the kind of objects you have in scores, Im guessing they are plain NStrings. In that case this should work:
NSArray *sortedArray = [scores sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger first = [(NSString *)a intValue];
NSDate *second = [(NSString *)b intValue];
return [first compare:second];
}];
NSMutableDictionary *directory = [NSMutableDictionary dictionary];
[directory setObject:[friends valueForKey:#"id"] forKey:#"id"];
[directory setObject:[friends valueForKey:#"name"] forKey:#"name"];
[directory setObject:sortedScoresArray forKey:#"score"];
I'm trying to get an array of keys where the value for the corresponding key in an NSDictionary is #YES.
For EG,:
Starting Dictionary:
NSDictionary* dict = #{#"key1" : #YES, #"key2": #YES, #"key3": #NO, #"key4": #NO};
Desired Result:
NSArray* array = #[#"key1", #"key2"];
I tried doing this with NSPredicates and subpredicates but couldn't find one that did what i wanted. My "working" but ugly solution is:
NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:0];
NSDictionary* dict = #{#"key1" : #YES, #"key2": #YES, #"key3": #NO, #"key4": #NO};
for (NSString* key in [dict allKeys]) {
if ([[dict objectForKey:key] isEqualToNumber:#YES])
[array addObject:key];
}
What is a better way of doing this, possibly with NSPredicates?.
This kind of abstracts a lot of the messiness away
NSArray *results = [dict keysOfEntriesPassingTest:^(id key, id obj, BOOL *stop) {
return [obj isEqualToNumber:#YES];
}].allObjects;
NSLog(#"%#", results);
I have the following NSArray containing NSDictionary(s):
NSArray *data = [[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1], #"bill", [NSNumber numberWithInt:2], #"joe", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:3], #"bill", [NSNumber numberWithInt:4], #"joe", [NSNumber numberWithInt:5], #"jenny", nil],
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:6], #"joe", [NSNumber numberWithInt:1], #"jenny", nil],
nil];
I am wanting to create a filtered NSArray that only contains objects where the NSDictionary matches multiple 'keys' using NSPredicate.
For example:
filter the array to only contain the NSDictionary objects that have keys "bill" and "joe" [desired result: new NSArray would contain the first two NSDictionary objects]
filter the array to only contain the NSDictionary objects that have keys "joe" and "jenny" [desired result: new NSArray would contain the last two NSDictionary objects]
Can anyone please explain the format of the NSPredicate to achieve this?
Edit:
I can achieve a similar outcome to desired NSPredicate using:
NSMutableArray *filteredSet = [[NSMutableArray alloc] initWithCapacity:[data count]];
NSString *keySearch1 = [NSString stringWithString:#"bill"];
NSString *keySearch2 = [NSString stringWithString:#"joe"];
for (NSDictionary *currentDict in data){
// objectForKey will return nil if a key doesn't exists.
if ([currentDict objectForKey:keySearch1] && [currentDict objectForKey:keySearch2]){
[filteredSet addObject:currentDict];
}
}
NSLog(#"filteredSet: %#", filteredSet);
I'm imagining NSPredicate would be more elegant if one exists?
they only way I know is to combine two conditions like "'value1' IN list AND 'value2' IN list"
self.#allKeys should return all the keys of the dictionary (self is each dictionary in your array). If you don't write it with the prefix # then the dictionary will just look for a key that is "allKeys" instead of the method "- (NSArray*) allKeys"
The code:
NSArray* billAndJoe = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%# IN self.#allKeys AND %# IN self.#allKeys" , #"bill",#"joe" ]];
NSArray* joeAndJenny = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%# IN self.#allKeys AND %# IN self.#allKeys" , #"joe",#"jenny" ]]
Since a dictionary just returns nil if you ask for a value of a non-existing key, it is enough to specify that the value should be non-nil. A format like the following should cover your first case:
[NSPredicate predicateWithFormat: #"%K != nil AND %K != nil", #"bill", #"joe"]
The second case, with "joe" and "jenny" follows a similar pattern, of course.
In a NSMutableDictionary like this:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithString:firstName], #"NAME",
[NSNumber numberWithFloat:familyName], #"SURNAME",
nil];
How can all of its elements be converted to the NSString? with the requirement that names and surnames are arranged in string like this: "name, surname, name, surname..."?
This gives a string with all the names but not surnames:
NSString * result = [[urlArray valueForKey:#"NAME"] componentsJoinedByString:#", "];
Is there a way similar to the one above to create a string with all the values of NSMutableDictionary?
Try something like this:
NSString *result = [NSString stringWithFormat:#"%#, %#", [urlArray valueForKey:#"SURNAME"], [urlArray valueForKey:#"NAME"]];
The %# represents an objective-c object for more details see the Apple docs
The code to make a NSString from an NSDictionary may look like (if you're trying to print out everything in the NSDictionary)
NSMutableString* mutableString = [NSMutableString string];
NSDictionary* dictionary;
for(NSString* key in [dictionary allKeys])
{
[mutableString appendString:[[dictionary objectForKey:key] description]];
}
I typed in text from a book and
I get this error: Passing argument of 1 of "initWithObjects:forKeys:count:" from incompatible pointer type
NSDictionary *dict = [[NSDictionary alloc] initWithObjects: #"hello", #"there", #"persn"
forKeys: #"aa", #"bb", #"cc"
count: 3 ];
NSLog(#"%#", [dict objectForKey: #"bb"]);
In Objective-C, methods can't use var-args like that, they must always come at the end of the invocation.
In fact, the parameters to your message invocation are actually pointers to buffers of objects and keys.
Try this:
id objects[] = {#"hello", #"there", #"person"};
id keys[] = {#"aa", #"bb", #"cc"};
NSDictionary *dict1 = [[NSDictionary alloc] initWithObjects:objects forKeys:keys count:3];
NSLog(#"%#", [dict1 objectForKey: #"bb"]);