为了账号安全,请及时绑定邮箱和手机立即绑定

目标C中从NSMutableArray中删除重复值的最佳方法-C?

目标C中从NSMutableArray中删除重复值的最佳方法-C?

iOS
暮色呼如 2019-07-27 15:15:17
目标C中从NSMutableArray中删除重复值的最佳方法-C?删除重复值的最佳方法(NSString)来自NSMutableArray目标-C?这是最简单和正确的方法吗?uniquearray = [[NSSet setWithArray:yourarray] allObjects];
查看完整描述

3 回答

?
达令说

TA贡献1821条经验 获得超6个赞


我知道这是一个老问题,但是在NSArray 如果你不关心命令.

如果我们用来自键值编码的对象运算符我们可以这样做:

uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];

安托巴还注意到,可以根据属性删除重复项。例如:@distinctUnionOfObjects.name



查看完整回答
反对 回复 2019-07-28
?
狐的传说

TA贡献1804条经验 获得超3个赞

是的,使用NSSet是一种明智的方法。

为了补充Jim Puls的回答,这里有一种在保留订单的同时剥离副本的替代方法:

// Initialise a new, empty mutable array NSMutableArray *unique = [NSMutableArray array];for (id obj in originalArray) {
    if (![unique containsObject:obj]) {
        [unique addObject:obj];
    }}

它基本上与Jim的方法相同,但将唯一项复制到一个新的可变数组中,而不是从原始数组中删除重复项。这使得在具有大量重复(不需要复制整个数组的副本)的大型数组的情况下,它的内存效率略高一些,而且在我看来,它的可读性更高一些。

请注意,在任何一种情况下,都要检查目标数组中是否已经包含了项(使用containsObject:在我的例子中,或者indexOfObject:inRange:(在Jim‘s中)不能很好地扩展到大型数组。这些检查在O(N)时间内运行,这意味着如果将原始数组的大小增加一倍,那么每张支票要跑两倍的时间。由于您正在对数组中的每个对象进行检查,您还将运行更多的这些更昂贵的检查。整个算法(我的和Jim的)运行在O(N)中2)时间,随着原始数组的增长,时间很快就会变得昂贵。

要将其降到O(N)时间,您可以使用NSMutableSet存储已添加到新数组中的项的记录,因为NSSet查找是O(1)而不是O(N)。换句话说,无论集合中有多少元素,检查一个元素是否是NSSet的成员都需要相同的时间。

使用这种方法的代码如下所示:

NSMutableArray *unique = [NSMutableArray array];NSMutableSet *seen = [NSMutableSet set];for (id obj in originalArray) {
    if (![seen containsObject:obj]) {
        [unique addObject:obj];
        [seen addObject:obj];
    }}

不过,这看起来还是有点浪费;当问题表明原来的数组是可变的时,我们仍然在生成一个新数组,因此我们应该能够将它降到适当的位置,并节省一些内存。就像这样:

NSMutableSet *seen = [NSMutableSet set];NSUInteger i = 0;while (i < [originalArray count]) {
    id obj = [originalArray objectAtIndex:i];

    if ([seen containsObject:obj]) {
        [originalArray removeObjectAtIndex:i];
        // NB: we *don't* increment i here; since
        // we've removed the object previously at
        // index i, [originalArray objectAtIndex:i]
        // now points to the next object in the array.
    } else {
        [seen addObject:obj];
        i++;
    }}

更新Yuri Niyazov指出我的最后一个答案实际上是O(N)2)因为removeObjectAtIndex:可能在O(N)时间内运行。

(他说“可能”是因为我们不确定它是如何实现的;但一个可能的实现是,在删除索引X处的对象之后,该方法循环遍历从索引X+1到数组中的最后一个对象的每个元素,然后将它们移动到前一个索引。如果是这样的话,那就是O(N)的性能。

那么,该怎么办呢?这要视情况而定。如果你有一个很大的数组,而且你只需要少量的重复,那么就地去复制就可以正常工作了,这样你就不必构建一个重复的数组了。如果您有一个数组,您需要大量的重复,那么构建一个单独的、去欺骗的数组可能是最好的方法。这里的方法是,大O表示法只描述一个算法的特性,它不会确切地告诉你哪种方法对任何给定的情况都是最好的。



查看完整回答
反对 回复 2019-07-28
  • 3 回答
  • 0 关注
  • 396 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信