【问题标题】:How to swap `NSMutableDictionary` key and values in place?如何交换“NSMutableDictionary”键和值?
【发布时间】:2013-10-15 17:44:10
【问题描述】:

我有一个NSMutableDictionary,我想交换值和键。即,交换值后成为键,其对应的键与成为值所有键和值都是唯一的。由于尺寸非常大,正在寻找合适的解决方案。此外,键和值是NSString 对象

【问题讨论】:

  • 是否保证没有重复值的键,反之亦然?
  • 是的,键是自动生成的 id,值是字符串。

标签: iphone ios nsmutabledictionary


【解决方案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 }

假设

  • 唯一值(因为它们将成为键)
  • 值符合NSCopying(同上)
  • 没有值等于任何键(否则冲突的名称将在此过程中丢失)

【讨论】:

  • 如果一个键与另一个(或任何)键的值相同,则不起作用。
  • @Jim 当然,但 OP 保证问题中的键/值唯一性
  • 我认为您不想在迭代集合时对其进行修改。
  • 枚举集合是[d allKeys],在枚举过程中没有发生变异。
  • @pedro.m,OP声明他们是NSString,所以它符合NSCopying
【解决方案2】:

这是另一种反转字典的方法。对我来说最简单的。

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.

【讨论】:

  • 与许多其他答案一样,它忽略了要点:它没有到位。
  • @GabrielePetronella 对不起。但如果您有性能或内存问题,也许您可​​以使用-allKeysForObject: 进行反向查找。没有分配,没有复制。
  • 这不是我,而是问题中需要它的 OP。
  • @GabrielePetronella 我明白了。我对“就地”的理解略有不同。最后,如果你做[d setDictionary:invertedDictionary];,你有没有到位? :)
  • 不完全是,从某种意义上说,您正在为创建 invertedDictionary 分配额外的内存,这是 OP 不想要的。
【解决方案3】:

编辑:我写了几行代码让 OP 开始创建自己的算法。答案没有得到很好的接受,所以我精心设计了一个算法的完整实现,它可以按照他的要求做,并且更进一步。

优点:

  • 不对字典的内容做任何假设,例如,值不需要符合“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; 
}

如您所见,不仅在层次结构的第一级交换了键和值,而且在每个集合的深处都交换了。

"&lt;30b50617&gt;" 表示封装在 NSValue 中的 UIView 对象。由于 UIView 不符合 NSCopying 协议,因此如果您希望它成为您的集合中的键,则需要这样处理。

注意:代码在几分钟内完成。如果我错过了什么,请告诉我。

【讨论】:

  • 我没有仔细阅读所有代码,但它看起来对这项任务来说有点矫枉过正
【解决方案4】:
for (NSString *key in [myDictionary allKeys]) {
     NSString *value = [responseDataDic objectForKey:key];
     [myDictionary removeObjectForKey:key];
     [myDictionary addObject:key forKey:value];
}

假设: 没有键=值;

复杂性: 不需要额外的空间。将循环一次并替换所有键值对。

【讨论】:

  • -1 这甚至不能编译。 getObjectForKey 不存在,您不能像这样循环遍历字典。也就是说,即使您修复了明显的错误,其核心概念也与公认的答案相同,因此不会增加任何价值。
  • @GabrielePetronella 只是一个细节:你可以像这样遍历字典。
  • @GabrielePetronella 抱歉这个错误,我忘记了它的 objectForKey。我可以使用 for(NSStrig *key in myDictionary) 遍历一个字典,其中 myDictionary 是一个有效的字典。
  • @iMartin 是的,我的错,尽管在迭代集合时对其进行变异仍然是个坏主意。
  • @GabrielePetronella 没错,他失踪了-copy
【解决方案5】:
NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];

【讨论】:

  • 按照 OP 的要求,它没有到位
  • 您可能打算将 allKeys 与 allValues 交换?在任何情况下,allValues 返回的元素的顺序都没有定义,因此这可能会关联错误的元素。
猜你喜欢
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 2015-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多