How to swap `NSMutableDictionary` key and values in place?

独自空忆成欢 提交于 2019-12-10 12:55:43

问题


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


回答1:


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)



回答2:


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.



回答3:


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.




回答4:


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.




回答5:


NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];


来源:https://stackoverflow.com/questions/19387631/how-to-swap-nsmutabledictionary-key-and-values-in-place

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!