Get all keys of a multidimensional dictionary - objective-c

I have a dictionary like:
{
dataTypes = (
{
dataType = "datatype1";
editable = 1;
maxValue = 300;
minValue = 0;
order = 1;
title = "Title 1";
type = numeric;
units = kg;
},
{
dataType = "datatype 2";
editable = 1;
maxValue = 300;
minValue = 0;
order = 2;
title = "title2";
type = numeric;
units = gm;
},
{
dataType = "datatype3";
editable = 1;
maxValue = 300;
minValue = 20;
order = 3;
title = "title3";
type = numeric;
units = kg;
}
);
name = "Name";
order = 1
title = "Title";
}
I want to get all keys within this dictionary.
I tried [myDict allKeys], however this is returning only four keys: DataTypes, name, order, title.
I want to retrieve all keys: dataType, editable, maxvalue, etc.

Try this.
NSArray *tempArray = [myDict objectForKey:#"dataTypes"];
NSDictionary *tempDictionary = (NSDictionary *)tempArray[0];
[tempDictionary allKeys] will have what you want.
Write this method.
- (NSDictionary *)dictionaryFromArrayWithinDictionary:(NSDictionary *)dictionary withKey:(NSString *)key{
NSArray *tempArray = [dictionary objectForKey:key];
return (NSDictionary *)tempArray[0];
}
This will return the inner dictionary and simply calling `allKeys' on this dictionary, you will get all the keys you want.

You need to recursively walk through your dictionary, and through any arrays the dictionary might contain, and so on. This can be nicely done via a recursiveKeys method added to all objects, which returns an empty array for objects that are not containers, and walks though the container for objects that are containers:
#interface NSObject(MyCategory)
- (NSArray)recursiveKeys;
#end
#implementation NSObject(MyCategory)
- (NSArray)recursiveKeys {
return #[];
}
#end
#implementation NSArrray(MyCategory)
- (NSArray)recursiveKeys {
NSMutableArray *result = [NSMutableArray array];
for (id item in self) {
[result addObjectsFromArray:[item recursiveKeys]];
}
return [result copy]; //return an immutable array
}
#end
#implementation NSSet(MyCategory)
- (NSArray)recursiveKeys {
NSMutableArray *result = [NSMutableArray array];
for (id item in self) {
[result addObjectsFromArray:[item recursiveKeys]];
}
return [result copy]; //return an immutable array
}
#end
#implementation NSDictionary(MyCategory)
- (NSArray)recursiveKeys {
NSMutableArray *result = [self.allKeys mutableCopy];
for (id key in self) {
[result addObjectsFromArray:[self[key] recursiveKeys];
}
return [result copy]; //return an immutable array
}
#end
You can use it like this:
NSArray *keys = myDictionary.recursiveKeys;
Please pardon any syntax errors, I don't have at this time an Xcode in front of me, I simply typed the code here on SO.

Related

ObjectForKey is returning nil sometimes

I am trying to set an object to a dictionary with key as an object. The test cases works fine, but within the actual code, I am not able to get the value for the key. The NSMutableDictionary has the key value in it, but when debugging it returns nil.
#implementation JSHashMap {
NSMutableDictionary *dict;
}
- (instancetype)initWithArray:(NSMutableArray *)array {
self = [super init];
if (self) {
dict = [self fromArray:array];
}
return self;
}
- (NSMutableDictionary *)fromArray:(NSMutableArray *)array {
NSMutableDictionary* _dict = [NSMutableDictionary new];
NSUInteger i = 0, len = [array count];
if (len % 2 != 0) {
error(#"JSError: Odd number of elements in the array.");
return _dict;
}
for (i = 0; i < len; i = i + 2) {
[_dict setObject:array[i + 1] forKey:array[i]];
assert([_dict objectForKey:array[i]] != nil);
}
debug(#"%#", _dict);
return _dict;
}
- (JSData *)objectForKey:(id)key {
return [dict objectForKey:key];
}
I am creating the hash map using the initWithArray method.
(lldb) po [dict objectForKey:key]
nil
The key passed in and the key in the dictionary has the same memory address 0x100ea2fa0.
The test cases works fine though. But the when running the actual program, it fails.
NSMutableDictionary *dict = [NSMutableDictionary new];
JSNumber *val = [[JSNumber alloc] initWithInt:1];
JSNumber *key = [[JSNumber alloc] initWithInt:2];
[dict setObject:val forKey:key];
JSData * ret = [dict objectForKey:key];
XCTAssertNotNil(ret);
XCTAssertEqualObjects([ret dataType], #"JSNumber");
JSHashMap *hm = [[JSHashMap alloc] initWithArray:[#[key, val] mutableCopy]];
JSData * ret1 = [hm objectForKey:key];
XCTAssertNotNil(ret1);
XCTAssertEqualObjects([ret1 dataType], #"JSNumber");
JSHashMap *dict = (JSHashMap *)ast;
NSArray *keys = [dict allKeys];
NSUInteger i = 0;
NSUInteger len = [keys count];
for (i = 0; i < len; i++) {
id key = keys[i];
JSData *val = (JSData *)[dict objectForKey:key];
// Issue -> val is getting nil
}
How to fix this and why is this random behaviour?
Found the failing test case.
NSArray *keys = [hm allKeys];
XCTAssertTrue([keys count] == 1);
JSData *ret = [hm objectForKey:keys[0]];
XCTAssertNotNil(ret);
If I use the key returned from calling allKeys method, it returns nil.
You have not shown any information about what JSNumber is, but I am betting that it does not implement isEqual and hash correctly. Thus, you cannot successfully use it as a key in an NSDictionary.

Parse NSDictionary in NSArray created from JSON in Objective-C

I'm trying to get information out of this Dictionary that was created from a JSON string. The JSON string is returned from the server and is put in a dictionary. That dictionary is passed to myMethod that is suppose to break it down so I can get the information that each record contains.
The "Recordset" is an Array. The Record is also an array of dictionaries.
How do I get to the dictionaries? I keep getting NSDictionaryM objectAtIndex: unrecognized selector sent to instance
Recordset = (
{
Record = (
{
MODMAKlMakeKey = 1112;
MODlModelKey = 1691;
MODvc50Name = "10/12 Series 2";
},
{
MODMAKlMakeKey = 1112;
MODlModelKey = 1687;
MODvc50Name = "10/4";
},
{
MODMAKlMakeKey = 1112;
MODlModelKey = 1686;
MODvc50Name = "10/6";
},
etc .. etc... ( about 100 records )
Here is what I have
- (void) myMethod : (NSDictionary*) dictionary {
//INITIAL
NSArray * arrRecordSet = [dictionary objectForKey:#"Recordset"];
NSArray * arrRecord = [arrRecordSet objectAtIndex:0];
NSDictionary * theRecord = [NSDictionary dictionaryWithObjects:arrRecord forKeys:[arrRecord objectAtIndex:0]];
for (int i = 0; i < arrRecord.count; i++) {
NSLog(#"MODMAKlMakeKey: %#", [theRecord objectForKey:#"MODMAKlMakeKey"]);
}
}
Try this
NSArray * arrRecord = [arrRecordSet objectForKey:#"Record"];
Try to check first if the return of [dictionary objectForKey:#"Recordset"] is really a dictionary or an array.
To do this:
if([[dictionary objectForKey:#"Recordset"] isKindOfClass:[NSArray class]]) {
//object is array
}
else if ([[dictionary objectForKey:#"Recordset"] isKindOfClass:[NSDictionary class]]) {
//object is dictionary
}

Parsing multiple row from json info in objective-c

My json stiring is:
{
"locations" :[
{
id = 0;
lat = "41.653048";
long = "-0.880677";
name = "LIMPIA";
},
{
id = 1;
lat = "41.653048";
long = "-0.890677";
name = "LIMPIA2";
}
]
}
Using:
NSDictionary * root = [datos_string1 JSONValue];
NSArray *bares = (NSArray *) [root objectForKey:#"locations"];
for (NSArray * row in bares) {
NSString *barName1 = [bares valueForKey:#"name"];
NSLog(#"%#",barName1);
}
I obtain from NSlog , twice otput
(
LIMPIA,
LIMPIA2
)
So somthing is wrong. I need to estract di single value parameter (lat, lon and nombre) for each item (in order to use in a mapkit app). Could you help me?
I need to estract di single value parameter (lat, lon and nombre) for each item (in order to use in a mapkit app)
If I understand your question correctly, you're trying to access each value in each dictionary in the locations array, is that right?
In order to access each value (if that is indeed your question), this should work:
NSDictionary *root = [datos_string1 JSONValue];
NSArray *bares = (NSArray *)[root objectForKey:#"locations"];
// Each item in the array is a dictionary, not an NSArray
for (NSDictionary *dict in bares) {
// Loop over keys
for (NSString *key in [dict allKeys]) {
NSLog(#"dict[%#] == %#", key, [dict objectForKey:key]);
}
}

Reversing "columns" in a table made from a NSArray

I have a NSArray made out of numbers 1..50, which represents a table with columns & rows.
I need to reverse only the order of the columns, while keeping the order of the rows.
So for example:
0,1,2,3,4,5,6
7,8,9,9,10,11,12
has to be
6,5,4,3,2,1,0
12,11,10,9,8,7
Right now, i use a huge IF statement for that:
for (dd *d in dates[i]) {
if (tileNum==0) {
reversedTileNum = 6;
} else if (tileNum==1) {
reversedTileNum = 5;
}else if (tileNum==2) {
reversedTileNum = 4;
}else if (tileNum==3) {
reversedTileNum = 3;
}else if (tileNum==4) {
reversedTileNum = 2;
}else if (tileNum==5) {
reversedTileNum = 1;
} else if (tileNum==6) {
reversedTileNum = 0;
}
....
....
}
Here's a solution that should be easy to drop into any project. It involves two categories: one on NSMutableArray that provides a method to swap objects at two indices, and one on NSArray that provides the -arrayByReversingGroups: method. The idea is to swap the elements in pairs within a group, reversing the group. If number of elements in the array isn't an even multiple of groupSize, the extras at the end are left untouched.
The code presented here is a complete program, so you can see an example of using -arrayByReversingGroups: in the main() function.
#import <Foundation/Foundation.h>
#interface NSArray(Reversible)
-(NSArray*)arrayByReversingGroups:(int)groupSize;
#end
#interface NSMutableArray(Swappable)
-(void)swapObjectAtIndex:(int)first withObjectAtIndex:(int)second;
#end
#implementation NSArray(Reversible)
-(NSArray*)arrayByReversingGroups:(int)groupSize
{
NSMutableArray *newArray = [self mutableCopy];
// Iterate over the array in chunks of groupSize elements. i will be first index in
// the current chunk.
for (int i = 0; (i + groupSize) < [newArray count]; i += groupSize) {
// Iterate over the items in the current chunk, swapping the bth and
// (groupsize-b-1)th elements until they meet at groupsize/2.
for (int b = 0; b <= (groupSize / 2); b++) {
int first = i + b;
int second = i + groupSize - b - 1;
[newArray swapObjectAtIndex:first withObjectAtIndex:second];
}
}
return [newArray copy];
}
#end
#implementation NSMutableArray(Swappable)
-(void)swapObjectAtIndex:(int)first withObjectAtIndex:(int)second
{
id temp = [[self objectAtIndex:second] retain];
[self replaceObjectAtIndex:second withObject:[self objectAtIndex:first]];
[self replaceObjectAtIndex:first withObject:temp];
[temp release];
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSArray *array = [NSArray arrayWithObjects:
#"1", #"2", #"3", #"4", #"5", #"6", #"7", #"8", #"9", #"10", #"11", #"12", nil];
NSLog(#"Original: %#", array);
NSLog(#"Reversed: %#", [array arrayByReversingGroups:5]);
}
return 0;
}
I can give you the logic.. you will have to write the code...
First create a function where you pass in an array(here you will send in a row.) then in this function create a new tempeorary array and store all the values for that row in this column then overwrite the original array in reverse order from this new array and return this to the full matrix and store it in there ... hope it helps.

Optimizing a for in loop with NSMutableDictionary

I have an NSMutableDictionary that contains a MPMediaItem and a string of it's title for it's key. I currently have 1,777 items in the dictionary.
I am looping through the dictionary looking for a fuzzy match with a supplied NSString. How can I speed it up? It takes about 6 seconds every time it's run.
I'll just past in the loop itself
#autoreleasepool {
float currentFoundValue = 1000.0;
NSMutableArray *test;
MPMediaItemCollection *collection;
float match;
for(id key in artistDictionary)
{
NSString *thisArtist = key;
int suppliedCount = [stringValue length];
int keyCount = [thisArtist length];
if(suppliedCount > keyCount)
{
match = [StringDistance stringDistance:thisArtist :stringValue];
} else {
match = [StringDistance stringDistance:stringValue :thisArtist];
}
if(match < currentFoundValue)
{
currentFoundValue = match;
test = [artistDictionary objectForKey:thisArtist];
collection = [[MPMediaItemCollection alloc] initWithItems:test];
}
}
...
See -enumerateKeysAndObjectsWithOptions:usingBlock:, and use the NSEnumerationConcurrent option.
You have two performance bootle necks:
You potentially recreate the MPMediaItemCollection instance once for each iteration, when only the last one created is needed.
-[NSDictionary enumerateKeysAndObjectsWithOptions:usingBlock:] is much faster when both the key and value of the enumerated dictionary is needed.
Change into something like this:
float currentFoundValue = 1000.0;
NSMutableArray *test = nil;
MPMediaItemCollection *collection;
float match;
[artistDictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id key, id obj, BOOL *stop)
{
NSString *thisArtist = key;
int suppliedCount = [stringValue length];
int keyCount = [thisArtist length];
if(suppliedCount > keyCount)
{
match = [StringDistance stringDistance:thisArtist :stringValue];
} else {
match = [StringDistance stringDistance:stringValue :thisArtist];
}
if(match < currentFoundValue)
{
currentFoundValue = match;
test = obj;
}
}];
collection = [[MPMediaItemCollection alloc] initWithItems:test];