【问题标题】:NSDictionary: is order of iteration preserved?NSDictionary:是否保留了迭代顺序?
【发布时间】:2021-03-04 20:05:45
【问题描述】:

假设我想访问某个 NSDictionary 对象中的所有对象。 我想这样迭代:

for (key in dict){}

是否保证每次运行字典中的对象都以相同的顺序被访问?

PS。让我更彻底地解释我的问题:如果我迭代字典一次并以某种具体顺序访问键 - 我会在 第二次 迭代尝试中获得 same 顺序吗?

【问题讨论】:

  • 我的问题是不同的:如果我迭代字典一次并以某种具体顺序访问键 - 我在第二次迭代尝试时会有相同的顺序吗?
  • 什么是存储值数据类型、混合 id 或自定义类对象?

标签: ios objective-c macos cocoa


【解决方案1】:

文档指出,对于 allKeys 属性,未定义数组中元素的顺序。

因此,您只需对键数组进行排序以确保它始终是排序的。

【讨论】:

    【解决方案2】:

    每次迭代都将按随机顺序排列,因为 Swift 字典不会优先排序。但是,数组确实如此,因此您可以对字典进行排序(按键或值)以生成元组数组,实际上可以将其视为已排序的字典。

    let dictionary = ["k4": 3, "k2": 8, "k1": 6]
    let sortedArrayOfTuples = dictionary.sorted(by: { $0.key < $1.key })
    
    for entry in dictionary {
        print(entry.key)
    }
    
    for entry in sortedArrayOfTuples {
        print(entry.key)
    }
    

    【讨论】:

      【解决方案3】:

      由于密钥放置在NSDictionary 内的性质,不能保证对密钥进行排序。但这只是一半的答案。继续阅读...

      如果我们使用 for (NSString* key in dict) 循环遍历 dict,或者
      使用 for 甚至更不具体(id key in dict) 循环然后我们实际上使用NSEnumeration。这些迭代对你来说是不可预测的。 NSEnumeration 和 NSFastEnumeration 不要使用索引迭代字典。可以这么说,它们通过地址或密钥的哈希值来遍历。这也是一个不完整的模糊答案。

      字典中的键与同一字典中的其他键相比是唯一的。 这是伟大的事情,为什么你会使用NSDictionary或NSMutableDictionary而不是索引NSArray或NSPointerArray或不特定的NSSet,并特别提供数据类型为NSOrderedSet、NSOrderedCollection。 NSMapTable 和 NSHashTable 往往表现得像 NSDictionaries,但它们存储密钥和迭代的方式完全不同。

      那么当你在 NSDictionary 中重写一个键值时会发生什么?

      NSDictionary *dict = @{
          @"A" : @(1234),
          @"B" : @(4321)
      }
      NSMutableDictionary *mutabledict = [dict mutablecopy];
      mutabledict[@"A"] = @(5678); //beware this only works on NSMutableDictionary.
      dict = mutabledict;
      

      这里我们交换第一个声明的键 A 的值。
      mutabledict[@"A"] [key] 是一个 getter 下标,用于查找键的地址价值对。密钥本身没有任何改变。因此,密钥的顺序保持在复制唯一密钥的那一刻。 创建 mutablecopy 时需要小心,因为这样会复制整个对。排序的结果也可能是不可预测的。 很简单:但是访问键值不会改变它们的内存布局。

      但是:NSDictionary 是不可变的,因此一旦设置了键就不能更改。所以你可以说: 这些键是按照它们第一次存储的顺序排列的。但是,当您不知道键:值对的放置顺序以及通过此过程将其唯一键复制到字典中时,您无法访问以保证顺序存储的值。

      如果您无法控制设置键的顺序,那么您不知道键的顺序,(尊重问题)不是未定义的。而且 NSEnumeration 迭代无法让您真正了解它们的存储顺序。

      如何处理?

      获得已知的键排序排序的简单方法是手动排序所有键,例如..

      NSArray *sortedKeys = [dict.allKeys sortedArrayUsingSelector:@selector(compare:)];
      

      它为您提供键的升序,并允许您使用包含键地址的数组索引遍历您的字典。喜欢..

      for (unsigned int i=0; i<sortedKeys.count; i++) {
          NSString* key = sortedKeys[i];
          dict[ key ] = yourValue;
      }
      

      如果键不感兴趣但保证排序对您来说更重要,那么您可以将 NSDictionary 转换为没有键的排序 NSArray 并在循环中访问其索引。除非您手动存储它们,否则明显的回画没有键。

      id notfoundmarker = @"empty";
      NSArray *sortedkeys= [dict.allKeys sortedArrayUsingSelector:@selector(compare:)];
      NSArray *oneForOneSorted = [dict objectsForKeys:sortedkeys notFoundMarker:notfoundmarker];
      for (unsigned int i=0; i<oneForOneSorted.count; i++) {
          id<NSObject> value = oneForOneSorted[i];
          NSLog(@"%@", value);
      };
      

      【讨论】:

        【解决方案4】:

        我的问题不同:如果我迭代字典一次并以某种具体顺序访问键 - 我在第二次迭代尝试时是否会有相同的顺序?

        简答

        很有可能是的

        更长的答案

        没有指定字典的内部构造方式,并且有多种表示字典的方式,所有已知的是键值必须是可散列的,这意味着使用散列以某种方式。

        也不知道字典在枚举它们时使用什么算法来提供键,同样对于特定的可能表示,可能有多个枚举算法。

        所以我们有很多未知数。

        我们知道什么?

        在没有线程、随机数生成和任何类似功能的情况下,Objective-C 程序是确定性的,这是它与 C、Swift、Java、C# 和许多其他语言的共同特征。

        NSDictionary 不是线程安全的,因此不太可能在其实现中使用线程。

        为什么它会使用随机数?

        NSDictionary 也是一个不可变类型,因此一旦构建,就没有明显的理由重新排序其内部存储以响应查询其内容的调用。

        因此,很有可能,您将在每个枚举中获得相同的键顺序。

        没有来源虽然你不能确定,但​​你不能通过黑盒测试来证明不存在某些东西。也许程序员决定在每百万个枚举中加入一点随机性——只是为了好玩;-) 这可能吗?也许不是(这可能是被解雇的好方法!),但这不是不可能。

        如果你是出于好奇而问,那就保持好奇吧!

        但是,如果您想依靠确定性的顺序来确保代码的正确性,那么对键进行排序(如果您愿意,只要它具有确定性,就可以按照特殊的顺序进行排序),这样做的成本很可能 em> 无关紧要。

        HTH

        【讨论】:

        • developer.apple.com/library/archive/documentation/Cocoa/… NSDictionary 是线程安全的,它是不可变的。
        • @OlSen – 很好奇(或不足为奇?;-))因为我很确定它在 Apple 文档的某处说/说它不应该被视为线程安全的,尽管在逻辑上存在这不是一个很好的理由。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-14
        • 2015-09-06
        • 2010-10-14
        相关资源
        最近更新 更多