什么时候在NSArray上使用NSSet更好?


Answers:


173

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

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


9
log(1)vs log(n)
rohan-patel

25
@ rohan-patel正确的是O(1)vs O(n)
Mansurov Ruslan

1
如果订购:O(1)vs O(logn),因为二进制搜索是适用的。如果无序,则O(1)与O(n)
baskInEminence

180

Apple文档中的图像对此进行了很好描述:

Objective-C集合

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]

2
在您的示例中,您正在向数组和集合中添加基元。两者皆有可能,因为它们只能包含对象。
FreeAsInBeer 2012年

10
感谢您对@Zaheer的修改,但这实际上是无效的。我没有添加原语。我正在添加文字。
James Webster 2014年

很好的解释:) +1 :)
Karun 2014年

1
爱你的解释!为此+1
叛乱

66

最好的答案是苹果自己的文档

在此处输入图片说明

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

那里有几篇文章谈论这两者之间的速度差异,例如这篇文章。如果您要遍历无序集合,那就NSSet太好了。但是,在许多情况下,您需要做只能做的事情NSArray,因此您会牺牲这些能力的速度。

NSSet

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

NSArray

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

这就是全部!让我知道是否有帮助。


您不必NSSet为了索引而总是牺牲。对同一数据使用两种不同的数据结构是很常见的。或者,您可以在该数组上建立索引:)但是,最好使用已经实现了它的数据库。
Sulthan 2012年

“在该数组上建立索引”。您不能在NSSet上建立索引。您可以使用多种不同的技术。而且,如果您需要同时牺牲内存和处理能力,那么您做错了。
苏珊(Sulthan)2012年

由于问题是关于NSSetNSArray,因此我的回答是准确而完整的。是的,您可以构建其他数据结构,但是我只是比较这两个。
woz 2012年

我表示赞成,但是当您谈到牺牲时,您的回答是不正确的。如果您需要的某些功能NSArray和某些功能NSSet,则正确的答案不是“使用NSArray和牺牲性能”。答案是两者结合或使用不同的数据结构。
Sulthan 2012年

我会说,主要的区别是针对唯一对象,因为数组可以具有重复对象。订单方面是次要的。
malhal,2015年

12

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


9

NSArray

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

NSSet

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

7

数组用于按项目索引访问项目。任何项目都可以多次插入数组。数组保留其元素的顺序。

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

如果数组要检查是否包含元素,则必须检查其所有项目。集被设计为使用更快的算法。

您可以想象一个像没有值的字典的集合。

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

有关更多信息,请参见Wikipedia


实际上,仅需要检查数组才能找到该项目。如果项目在数组中,则很少需要检查每个项目。
FreeAsInBeer 2012年

是的,正如您所说的“如果项目在数组中”。如果您期望如此,则不必检查它是否在那里。contains操作的复杂度为O(n)。如果不在数组中,则比较次数为n。对象在数组中时的平均比较数为n/2。即使找到对象,性能也很糟糕。
Sulthan 2012年

只有在大型阵列中才能获得出色的性能。如果您知道数组可能会变得很大,那么可以使用多种方法来提高数组的性能,例如使用数组数组。
FreeAsInBeer 2012年

如果相等操作很昂贵,那么即使在包含3个项目的数组上,您也会看到差异。当您重复执行多次操作(例如,在“ for”循环中使用该操作)时,可能会发生与大型阵列相同的行为。您听说过摊销的复杂性吗?与一组相比(通常具有恒定的复杂性),复杂度仍然是线性的,并且性能糟透了。
苏珊(Sulthan)2012年

显然会有区别,我只是说,大的符号是指数的。如果阵列较小,则差异将很小。同样,NSArrays比s具有其他速度优势NSSet。与往常一样,这是一个折衷。
FreeAsInBeer 2012年

5
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)}


4

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

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

如果键被突变,则哈希(也可能)也会改变,指向哈希表中的其他索引/存储桶。原始值不会被删除,并且在枚举或询问结构的大小/计数时会被实际考虑在内。

这可能会导致某些很难找到的错误。


3

在这里,您可以找到NSArray和数据NSSet结构的相当全面的比较。

简短结论:

是的,NSArray在保持和迭代方面比NSSet快。构造速度快50%,迭代速度快500%。课程:如果只需要迭代内容,请不要使用NSSet。

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

NSDictionary的构建速度比NSMapTable慢-因为它需要复制关键数据。它通过更快的查找来弥补这一点。当然,两者具有不同的功能,因此在大多数情况下,应该在其他因素上做出确定。


虽然从理论上讲这可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。
Tunaki

2

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


1

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

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.