【问题标题】:When is it better to use an NSSet over an NSArray?什么时候使用 NSSet 而不是 NSArray 更好?
【发布时间】:2012-06-15 09:06:08
【问题描述】:

我在我的应用程序中多次使用 NSSet,但我自己从未创建过。

什么时候使用NSSet 比使用NSArray 更好,为什么?

【问题讨论】:

    标签: ios objective-c arrays cocoa cocoa-touch


    【解决方案1】:

    当集合中项目的顺序不重要时,集合为查找集合中的项目提供了更好的性能。

    原因是集合使用哈希值来查找项目(如字典),而数组必须遍历其全部内容才能找到特定对象。

    【讨论】:

    • @rohan-patel 正确的是 O(1) vs O(n)
    • 如果排序:O(1) vs O(logn),因为二进制搜索是适用的。如果无序,则 O(1) vs O(n)
    【解决方案2】:

    Apple's Documentation的图片描述的很好:

    Array 是一个有序(添加时保持顺序)元素序列

    [array addObject:@1];
    [array addObject:@2];
    [array addObject:@3];
    [array addObject:@4];
    [array addObject:@6];
    [array addObject:@4];
    [array addObject:@1];
    [array addObject:@2];
    
    [1, 2, 3, 4, 6, 4, 1, 2]
    

    Set 是一个不同(无重复)、无序元素列表

    [set addObject:@1];
    [set addObject:@2];
    [set addObject:@3];
    [set addObject:@4];
    [set addObject:@6];
    [set addObject:@4];
    [set addObject:@1];
    [set addObject:@2];
    
    [1, 2, 6, 4, 3]
    

    【讨论】:

    • 在您的示例中,您将原语添加到数组和集合中。两者都不可能,因为它们只能包含对象。
    • 感谢您的编辑@Zaheer,但实际上是无效的。我没有添加原语。我在添加文字。
    • 很好的解释 :) +1 :)
    • 喜欢你的解释!为此 +1
    • 对于有序的数据集合并且没有重复,您可以使用已经在 iOS 5 及更高版本中引入的 NSOrderedSet。
    【解决方案3】:

    最好的答案是Apple's own documentation

    主要区别在于NSArray 用于有序集合,NSSet 用于无序集合。

    有几篇文章讨论了两者之间的速度差异,例如this one。如果您正在遍历无序集合,NSSet 非常棒。但是,在许多情况下,您需要做只有 NSArray 才能做的事情,因此您牺牲了这些能力的速度。

    NSSet

    • 主要通过比较访问项目
    • 无序
    • 不允许重复

    NSArray

    • 可以按索引访问项目
    • 已订购
    • 允许重复

    这就是它的全部内容!让我知道这是否有帮助。

    【讨论】:

    • 您不必总是为了索引而牺牲NSSet。对相同的数据使用两种不同的数据结构是很常见的。或者您在该数组上构建和索引 :) 但是最好使用已经实现的数据库。
    • “在该数组上建立索引”。您不能在 NSSet 上创建索引。您可以使用许多不同的技术。如果你需要同时牺牲内存和处理能力,那你就错了。
    • 由于问题是关于NSSetNSArray,所以我的回答是准确而完整的。是的,您可以构建其他数据结构,但我只是比较这两个。
    • 我确实投了赞成票,但是当您谈到牺牲时,您的回答不正确。如果您需要NSArray 的一些功能和NSSet 的一些功能,正确的答案不是“使用NSArray 并牺牲性能”。答案是结合两者或使用不同的数据结构。
    • 我会说主要区别在于设置的唯一对象是数组可以有重复项。订单方面是次要的事实。
    【解决方案4】:

    数组用于通过索引访问项目。任何项目都可以多次插入到数组中。数组保持其元素的顺序。

    一个集合基本上只用于检查项目是否在集合中。这些项目没有顺序或索引的概念。你不能在一个集合中拥有两次。

    如果一个数组想要检查它是否包含一个元素,它必须检查它的所有元素。集合旨在使用更快的算法。

    你可以把集合想象成一个没有值的字典。

    请注意,数组和集合不是唯一的数据结构。还有其他的,例如队列、堆栈、堆、斐波那契堆。我会推荐阅读一本关于算法和数据结构的书。

    更多信息请参见wikipedia

    【讨论】:

    • 实际上,数组只需要检查到找到该项目为止。如果项目在数组中,则很少需要检查每个项目。
    • 是的,正如您所说的“如果项目在数组中”。如果您期望这一点,则不必检查它是否存在。 contains 操作的复杂度是O(n)。不在数组中时的比较次数为n。对象在数组中时的平均比较次数为n/2。即使找到对象,性能也很糟糕。
    • 只有大型阵列的性能才会很糟糕。如果您知道数组可能会变得非常大,那么您可以通过一些方法来提高数组的性能,例如使用数组数组。
    • 如果相等操作代价高昂,即使在包含 3 个项目的数组上,您也会看到差异。当您多次重复该操作(例如,在“for”循环中使用该操作)时,可能会发生与大型数组相同的行为。你听说过摊销复杂性吗?复杂性仍然是线性的,与一组(通常具有恒定的复杂性)相比,性能很糟糕。
    • 显然会有区别,我只是说大 o 符号是指数的;对于小型阵列,差异将是微乎其微的。此外,NSArrays 比 NSSets 具有其他速度优势。与往常一样,这是一种权衡。
    【解决方案5】:

    NSOrderedSet 在 iOS 5+ 中可用,因此主要区别在于您是否想要数据结构中的重复对象。

    【讨论】:

      【解决方案6】:

      主要区别已经在其他答案中给出。

      我只想指出,由于集合和字典的实现方式(即使用哈希),应注意不要将可变对象用作键。

      如果一个键发生了变异,那么哈希值也会(可能)发生变化,指向哈希表中的不同索引/存储桶。原始值不会被删除,并且在枚举或询问结构的大小/计数时实际上会被考虑在内。

      这可能会导致一些非常难以定位的错误。

      【讨论】:

        【解决方案7】:
        NSArray *Arr;
        NSSet *Nset;
        
        Arr=[NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"2",@"1", nil];
        Nset=[NSSet setWithObjects:@"1",@"2",@"3",@"3",@"5",@"5", nil];
        
        NSLog(@"%@",Arr);
        NSLog(@"%@",Nset);
        

        数组

        2015-12-04 11:05:40.935 [598:15730] (1, 2, 3, 4, 2, 1)

        集合

        2015-12-04 11:05:43.362 [598:15730] { ( 3, 1, 2, 5 )}

        【讨论】:

          【解决方案8】:

          NSArray

          1. 有序的数据收集
          2. 允许重复
          3. 是集合类型的对象

          NSSet

          1. 数据的无序收集
          2. 不允许重复
          3. 也是集合类型的对象

          【讨论】:

            【解决方案9】:

            Here 你可以找到NSArrayNSSet 数据结构的相当全面的比较。

            小结:

            是的,NSArray 比 NSSet 简单地保持和迭代更快。构建速度快 50%,迭代速度快 500%。教训:如果您只需要迭代内容,请不要使用 NSSet。

            当然,如果您需要测试是否包含,请努力避免使用 NSArray。即使你需要迭代和包含测试,你可能仍然应该选择一个 NSSet。如果您需要保持集合有序并测试是否包含,那么您应该考虑保留两个集合(一个 NSArray 和一个 NSSet),每个集合都包含相同的对象。

            NSDictionary 的构造比 NSMapTable 慢——因为它需要复制关键数据。它通过更快的查找来弥补这一点。当然,两者的能力不同,所以大多数时候,应该根据其他因素做出决定。

            【讨论】:

            • 虽然理论上这可以回答这个问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
            【解决方案10】:

            当访问速度至关重要且顺序无关紧要时,您通常会使用 Set,或者由其他方式(通过谓词或排序描述符)确定。例如,当通过一对多关系访问托管对象时,Core Data 使用集合

            【讨论】:

              【解决方案11】:

              只是为了添加一点,我有时使用 set 来从数组中删除重复项,例如:-

              NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
              

              【讨论】:

                猜你喜欢
                • 2011-06-26
                • 2010-10-28
                • 1970-01-01
                • 1970-01-01
                • 2014-10-08
                • 2012-01-15
                • 2013-05-15
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多