Как поменять местами ключ и значения` NSMutableDictionary'?


У меня есть NSMutableDictionary, и я хочу поменять местами значения и ключи. то есть, после замены значения становятся ключами, а его соответствующие ключи становятся значениями, все ключи и значения уникальны. Ищу решение на месте, потому что размер очень большой . Кроме того, ключи и значения являются объектами NSString

5 9

5 ответов:

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 }

Предположения

  • уникальные значения (поскольку они станут ключами)
  • значения соответствуют NSCopying (то же, что и выше)
  • никакое значение не равно ни одному ключу (в противном случае сталкивающиеся имена будут потеряны в процессе)

Вот еще один способ инвертировать словарь. Самое простое для меня.

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.

Правка: я написал несколько строк кода, чтобы заставить ОП приступить к задаче создания собственного алгоритма. Ответ не был хорошо принят, поэтому я создал полную реализацию алгоритма, который делает то, что он просит, и идет на один шаг дальше.

Преимущества:

  • не делает никаких предположений относительно содержания словаря, например, значения не должны соответствовать протоколу NSCopying
  • пересекает всю иерархию коллекции, меняя местами все ключи
  • это быстро, так как он использует рекурсию и быстрое перечисление
  • не изменяет содержание исходного словаря, он создает совершенно новый словарь

Код был реализован через категории для обеих коллекций:

@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

И...

@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
В качестве примера предположим, что у вас есть словарь со следующей структурой:
UIView *view = [[UIView alloc] init];
NSDictionary *dict = @{@"1" : @"a",
                       @"2" : @[ @{ @"5" : @"b" } ],
                       @"3" : @{@"6" : @"c"},
                       @"7" : view};

NSDictionary *newDict = [dict dictionaryBySwappingKeyWithValue];

Печать объекта newDict в консоли даст вам следующие выходные данные:

(lldb) po mutableDictionary
{
    a = 1;
    ({b = 5;}) = 2;
    {c = 6;} = 3;
    "<30b50617>" = 7; 
}

Как видите, ключи и значения поменялись местами не только на первом уровне иерархии, но и глубоко внутри каждой коллекции.

"<30b50617>" представляет объект UIView, заключенный в NSValue. Поскольку UIView не соответствует протоколу NSCopying, он должен быть обработан таким образом, если вы хотите, чтобы он был ключом в вашей коллекции.

Примечание: код был выполнен за пару минут. Дай мне знать, если я что-то упустил.
for (NSString *key in [myDictionary allKeys]) {
     NSString *value = [responseDataDic objectForKey:key];
     [myDictionary removeObjectForKey:key];
     [myDictionary addObject:key forKey:value];
}

Предположение: Нет ключа = значение;

Сложность: Никакого дополнительного пространства не требуется. Повторит цикл один раз и заменит все пары ключевых значений.

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