Transform NSDictionary - first array object becomes keys

Discussion in 'iOS Programming' started by theSeb, May 10, 2012.

  1. theSeb, May 10, 2012
    Last edited: May 10, 2012

    theSeb macrumors 604

    theSeb

    Joined:
    Aug 10, 2010
    Location:
    Poole, England
    #1
    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?
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    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]];
    }
    }
    
     
  3. theSeb, May 10, 2012
    Last edited: May 10, 2012

    theSeb thread starter macrumors 604

    theSeb

    Joined:
    Aug 10, 2010
    Location:
    Poole, England
    #3
    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!
     

Share This Page