Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I swap keys and values in NSDictionary?

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.

like image 822
hfossli Avatar asked Aug 27 '15 07:08

hfossli


People also ask

Can we swap keys and values in dictionary Python?

You can swap keys and values in a dictionary with dictionary comprehensions and the items() method.

Does NSDictionary retain objects?

An NSDictionary will retain it's objects, and copy it's keys. Here are some effects this has had on code I've worked on. Sometimes you get the same object you put in, sometimes not. Immutable objects are optimized to return themselves as a copy .

What is the difference between NSDictionary and NSMutableDictionary?

Main Difference is:NSMutableDictionary is derived from NSDictionary, it has all the methods of NSDictionary. NSMutableDictionary is mutable( can be modified) but NSDictionary is immutable (can not be modified).

How do you set a value in NSDictionary?

You have to convert NSDictionary to NSMutableDictionary . You have to user NSMutableDictionary in place of the NSDictionary . After that you can able to change value in NSMutableDictionary . Save this answer.


2 Answers

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.

like image 93
hfossli Avatar answered Dec 10 '22 21:12

hfossli


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.

like image 25
jscs Avatar answered Dec 10 '22 19:12

jscs