8

I want to know how to invert a NSDictionary.

I've seen some crazy code like

NSDictionary *dict = ...;
NSDictionary *swapped  = [NSDictionary dictionaryWithObjects:dict.allKeys forKeys:dict.allValues];

which is according to documentation not safe at all since the order of allValues and allKeys is not guaranteed.

hfossli
  • 22,616
  • 10
  • 116
  • 130

2 Answers2

7
NSDictionary *dict = ...;    
NSMutableDictionary *swapped = [NSMutableDictionary new];
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    swapped[value] = key;
}];

Note that the values should also conform to the NSCopying protocol.

hfossli
  • 22,616
  • 10
  • 116
  • 130
5

You're right, that code is crazy, but there are two ways to get an array of the values in the order given by an array of keys:

NSArray * keys = [dict allKeys];
NSArray * vals = [dict objectsForKeys:keys notFoundMarker:nil];

NSDictionary * inverseDict = [NSDictionary dictionaryWithObjects:keys
                                                         forKeys:vals];

Or

NSUInteger count = [dict count];
id keys[count];
id vals[count];
[dict getObjects:vals andKeys:keys];

NSDictionary * inverseDict = [NSDictionary dictionaryWithObjects:keys
                                                         forKeys:vals
                                                           count:count];

The former is obviously a lot nicer. As noted in hfossli's answer, the objects that were values in the original dictionary must conform to NSCopying in order to be used as keys in the inversion.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • Will these solutions work if the Values in the original dictionary (to become keys in the inverted dictionary) are not unique? I never tested the specific initializer under this constraint (having several recurring keys). – Motti Shneor Jun 16 '19 at 10:35