Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

theSeb

macrumors 604
Original poster
Aug 10, 2010
7,466
1,893
none
I am an old school C/C++ developer and I can't help but feel that I am doing this the wrong way. Is there a better way to transform an NSDictionary?

Let's say I have an NSDictionary that I load from a plist file and it looks like this

Code:
<plist version="1.0">
<dict>
	<key>0</key>
	<array>
		<string>US</string>
		<string>EU</string>
	</array>
	<key>1</key>
	<array>
		<string>100</string>
		<string>300</string>
	</array>
	<key>2</key>
	<array>
		<string>200</string>
		<string>600</string>
	</array>
</dict>
</plist>

So basically the keys are 0, 1, 2... and the objects are arrays. I now want to transform it so that the first row values are the keys (US and EU for example) and all of the corresponding values under that "column" become the values. In other words, for US, I should have an array of 100 and 200 and for EU I should have an array of 300 and 600.

I have written the following code and it works, but I feel like there should be some other way to do this using NSDictionary or perhaps using index path.

Code:
    NSArray *newKeys = [self.dictionary objectForKey:[NSString stringWithString:@"0"]];
    NSMutableDictionary *transformedDict = [NSMutableDictionary dictionary];
     
    for (NSUInteger i = 0; i < [newKeys count];i++)    
    {
        NSMutableArray *column = [NSMutableArray array];
        
        for (NSUInteger j = 1; j < [[self.dictionary allKeys] count];j++)
        {
            NSArray * val = [self.dictionary objectForKey:[NSString stringWithFormat:@"%d",j]];
            
            [column addObject:[val objectAtIndex:i]];
            
        }
        
        [transformedDict setValue:column forKey:[newKeys objectAtIndex:i]];
    }

What bothers me is that I am traversing through the dictionary many times, based on how many headings/columns there are and building up an array based on the heading index. It's not the most efficient way of doing it.

The point really is to be able to do this:

Code:
- (NSArray *)getColumnForKey:(NSString*) key
{
    return [self.transformedDictionary objectForKey:key];
}

Any ideas?
 
Last edited:
This code is untested and may not work. It might even kill you :eek:

I have assumed that the keys are sequential (no gaps)

Code:
NSArray *newKeys = [self.dictionary objectForKey:[NSString stringWithString:@"0"]];
int keyCount = [newKeys count];
int dictCount = [self.dictionary count]
// Want an array of arrays to store the values for each of the above keys.  Create the container array
NSMutableArray *newValues = [NSMutableArray arrayWithCapacity:keyCount];
// Then an array for each key
for (int i=0;i<newKeys;i++)
{
[newValues addObject:[NSMutableArray arrayWithCapacity[dictCount]]];
}

// Now we can loop over each non-key item in the dictionary and add each value to the arrays created above.  This will loop over the dictionary once.
for (int i=1;i<dictCount;i++)
{
// We should probably be more careful here: what if we get a dict with a non-array for a key?
NSArray *array = ((NSArray *) [self.dictionary objectForKey:[NSString stringWithFormat:@"%d",j]];)
for (int j=0;j<newKeys;j++)
{
[((NSMutableArray *) [newValues objectAtIndex:j]) addObject:[array objectAtIndex:j]];
}
}
 
Nice approach. There were a couple of minor semantic issues, but the code does indeed do what I wanted. Many thanks.

Code:
NSArray *newKeys = [self.dictionary objectForKey:[NSString stringWithString:@"0"]];
    int keyCount = [newKeys count];
    int dictCount = [self.dictionary count];
    // Want an array of arrays to store the values for each of the above keys.  Create the container array
    NSMutableArray *newValues = [NSMutableArray arrayWithCapacity:keyCount];
    // Then an array for each key
    for (int i=0;i < keyCount;i++)
    {
        [newValues addObject:[NSMutableArray arrayWithCapacity:dictCount]];
    }
    
    // Now we can loop over each non-key item in the dictionary and add each value to the arrays created above.  This will loop over the dictionary once.
    for (int i=1;i<dictCount;i++)
    {
        // We should probably be more careful here: what if we get a dict with a non-array for a key?
        NSArray *array = (NSArray *) [self.dictionary objectForKey:[NSString stringWithFormat:@"%d",i]];
        for (int j=0;j<keyCount;j++)
        {
            [((NSMutableArray *) [newValues objectAtIndex:j]) addObject:[array objectAtIndex:j]];
        }
    }

I then added this line and all my unit tests pass
Code:
return [NSDictionary dictionaryWithObjects:newValues forKeys:newKeys];

Great success!
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.