I have a NSMutableDictionary
and I want to swap values & keys. i.e, after swapping values becomes keys and its corresponding keys with become values All keys and values are unique. Looking for an in place solution because size is very big . Also, the keys and values are NSString
objects
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:@{
@"key1" : @"value1",
@"key2" : @"value2"}];
for (NSString *key in [d allKeys]) {
d[d[key]] = key;
[d removeObjectForKey:key];
}
NSLog(@"%@", d); // => { value1 : key1,
// value2 : key2 }
Assumptions
- unique values (as they will become keys)
- values conform to
NSCopying
(same as above) - no value is equal to any key (otherwise colliding names will be lost in the process)
[d allKeys]
, and that is not mutated during the enumeration. –
Leonaleonanie NSString
, so it conforms to NSCopying
–
Jonathanjonathon Here is another way to invert dictionary. The simplest for me.
NSArray *keys = dictionary.allKeys;
NSArray *values = [dictionary objectsForKeys:keys notFoundMarker:[NSNull null]];
[dictionary removeAllObjects]; // In case of huge data sets release the contents.
NSDictionary *invertedDictionary = [NSDictionary dictionaryWithObjects:keys forKeys:values];
[dictionary setDictionary:invertedDictionary]; // In case you want to use the original dictionary.
-allKeysForObject:
to do inversed lookup. No allocations, no copying. –
Elgar [d setDictionary:invertedDictionary];
you have it in place, or not? :) –
Elgar invertedDictionary
, which is what the OP doesn't want. –
Jonathanjonathon EDIT: I had written a few lines of codes to get the OP started into the task of creating his own algorithm. The answer was not well received so I have crafted a full implementation of an algorithm that does what he asks, and goes one step further.
Advantages:
- Makes no assumptions regarding the contents of the dictionary, for example, the values need not conform to the 'NSCopying' protocol
- Transverses the whole hierarchy of a collection, swapping all the keys
- It's fast since it uses recursion and fast enumeration
- Does not alter the contents of the original dictionary, it creates a brand new one
Code has been implemented through categories to both collections:
@interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue;
@end
@interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue
{
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:self.count];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
id newKey = nil;
if ([value isKindOfClass:[NSDictionary class]]) {
newKey = [value dictionaryBySwappingKeyWithValue];
} else if ([value isKindOfClass:[NSArray class]]) {
newKey = [value arrayBySwappingKeyWithValue];
} else {
newKey = value;
}
if (![newKey conformsToProtocol:@protocol(NSCopying)]) {
newKey = [NSValue valueWithNonretainedObject:newKey];
}
mutableDictionary[newKey] = key;
}];
return [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
@end
and...
@interface NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue;
@end
@implementation NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *newDict = [obj dictionaryBySwappingKeyWithValue];
mutableArray[idx] = newDict;
} else if ([obj isKindOfClass:[NSArray class]]) {
NSArray *newArray = [obj arrayBySwappingKeyWithValue];
mutableArray[idx] = newArray;
} else {
mutableArray[idx] = obj;
}
}];
return [NSArray arrayWithArray:mutableArray];
}
@end
As an example, assume you have a dictionary with the following structure:
UIView *view = [[UIView alloc] init];
NSDictionary *dict = @{@"1" : @"a",
@"2" : @[ @{ @"5" : @"b" } ],
@"3" : @{@"6" : @"c"},
@"7" : view};
NSDictionary *newDict = [dict dictionaryBySwappingKeyWithValue];
Printing the newDict
object in the console will give you this output:
(lldb) po mutableDictionary
{
a = 1;
({b = 5;}) = 2;
{c = 6;} = 3;
"<30b50617>" = 7;
}
As you can see, not only have the keys and values been swapped at the first level of the hierarchy, but deep inside each collection.
"<30b50617>"
represents the UIView object wrapped inside a NSValue. Since UIView does not comply to the NSCopying protocol, it needs to be handled this way if you want it to be a key in your collection.
Note: Code was done in a couple of minutes. Let me know if I missed something.
for (NSString *key in [myDictionary allKeys]) {
NSString *value = [responseDataDic objectForKey:key];
[myDictionary removeObjectForKey:key];
[myDictionary addObject:key forKey:value];
}
Assumption: No key = value;
Complexity: No extra space required. Will loop through once and replace all key value pairs.
getObjectForKey
does not exist, and you cannot loop through a dictionary like that. That said, even if you fix the obvious errors, the core concept it's identical to the accepted answer, so it's doesn't add any value. –
Jonathanjonathon -copy
. –
Elgar NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];
allValues
is not defined, therefore this might associate the wrong elements. –
Leonaleonanie © 2022 - 2024 — McMap. All rights reserved.