Как поменять местами ключ и значения` NSMutableDictionary'?
У меня есть NSMutableDictionary
, и я хочу поменять местами значения и ключи. то есть, после замены значения становятся ключами, а его соответствующие ключи становятся значениями, все ключи и значения уникальны. Ищу решение на месте, потому что размер очень большой . Кроме того, ключи и значения являются объектами NSString
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]; }
Предположение: Нет ключа = значение;
Сложность: Никакого дополнительного пространства не требуется. Повторит цикл один раз и заменит все пары ключевых значений.