Ios 在Objective-C中从NSMutableArray中删除重复值的最佳方法是什么?

Ios 在Objective-C中从NSMutableArray中删除重复值的最佳方法是什么?,ios,objective-c,nsmutablearray,Ios,Objective C,Nsmutablearray,从Objective-C中的NSMutableArray中删除重复值(NSString)的最佳方法是什么 这是最简单和正确的方法吗 uniquearray = [[NSSet setWithArray:yourarray] allObjects]; 如果您不担心对象的顺序,那么您的NSSet方法是最好的,但是,如果您不担心对象的顺序,那么为什么不首先将它们存储在NSSet中呢 我在2009年写了下面的答案;2011年,苹果在iOS 5和Mac OS X 10.7中添加了ensorderedse

从Objective-C中的
NSMutableArray
中删除重复值(
NSString
)的最佳方法是什么

这是最简单和正确的方法吗

uniquearray = [[NSSet setWithArray:yourarray] allObjects];

如果您不担心对象的顺序,那么您的
NSSet
方法是最好的,但是,如果您不担心对象的顺序,那么为什么不首先将它们存储在
NSSet
中呢

我在2009年写了下面的答案;2011年,苹果在iOS 5和Mac OS X 10.7中添加了
ensorderedset
。以前的算法现在是两行代码:

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];

如果您担心订单问题,并且您正在运行iOS 4或更早版本,请在阵列副本上循环:

NSArray *copy = [mutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
    if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
        [mutableArray removeObjectAtIndex:index];
    }
    index--;
}
[copy release];

只需使用以下简单代码:

NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];

由于nsset不允许重复值,并且所有对象都返回一个数组,因此以下是从NSMutable数组中删除重复值的代码。。它将适用于您。myArray是要删除重复值的可变数组

for(int j = 0; j < [myMutableArray count]; j++){
    for( k = j+1;k < [myMutableArray count];k++){
    NSString *str1 = [myMutableArray objectAtIndex:j];
    NSString *str2 = [myMutableArray objectAtIndex:k];
    if([str1 isEqualToString:str2])
        [myMutableArray removeObjectAtIndex:k];
    }
 } // Now print your array and will see there is no repeated value
for(int j=0;j<[myMutableArray count];j++){
对于(k=j+1;k<[myMutableArray count];k++){
NSString*str1=[myMutableArray objectAtIndex:j];
NSString*str2=[myMutableArray objectAtIndex:k];
if([str1 IsequalString:str2])
[myMutableArray removeObjectAtIndex:k];
}
}//现在打印数组,并将看到没有重复的值

是的,使用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:
,或者在Jim的示例中使用
indexOfObject:inRange:
)都不能很好地扩展大型数组。这些检查以O(N)时间运行,这意味着如果将原始数组的大小增加一倍,则每次检查的运行时间将是原来的两倍。由于您正在对阵列中的每个对象进行检查,因此您还将运行更多更昂贵的检查。整个算法(包括mine和Jim的)运行时间为O(N2)时间,随着原始阵列的增长,这一时间会很快变得昂贵

要将时间缩短到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++;
    }
}
但这似乎还是有点浪费;当问题明确表明原始数组是可变的时,我们仍在生成一个新数组,因此我们应该能够就地消除重复并节省一些内存。大概是这样的:

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++;
    }
}
NSMutableSet*seen=[NSMutableSet];
整数i=0;
而(i<[原始阵列计数]){
id obj=[原始数组对象索引:i];
如果([SEED containsObject:obj]){
[原始阵列移除对象索引:i];
//注:我们不在这里增加i;因为
//我们已在上一步移除该对象
//索引i,[原始数组对象索引:i]
//现在指向数组中的下一个对象。
}否则{
[见addObject:obj];
i++;
}
}

更新:尤里·尼亚佐夫(Yuri Niyazov),我的最后一个答案实际上是在O(N2)时间内运行的,因为
removeObjectAtIndex:
可能在O(N)时间内运行

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


那么,该怎么办?这要视情况而定。如果您拥有一个大型阵列,并且只需要少量的重复数据,那么就地重复数据消除就可以正常工作,从而避免您必须构建一个重复阵列。如果您有一个需要大量重复数据的阵列,那么构建一个单独的重复数据消除阵列可能是最好的方法。这里需要说明的是,big-O表示法只描述了一个算法的特征,它不会明确地告诉您哪一个最适合任何给定的情况。

在OS X v10.7及更高版本中可用

如果您担心订单,请选择正确的方法

NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];

以下是按顺序从NSArray中删除重复值的代码。

如果您的目标是iOS 5+(覆盖整个iOS世界),请最好使用SensorDeredSet。它删除重复项并保留
NSArray
的顺序

照办

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
现在可以将其转换回唯一的NSArray

NSArray *uniqueArray = orderedSet.array;
或者只使用orderedSet,因为它具有与NSArray相同的方法,如
objectAtIndex:
firstObject
等等

使用
contains
进行的成员资格检查在
ensorderedset
上比在
NSArray上更快


有关更多签出的信息,请注意,如果您有一个已排序的数组,则不需要检查数组中的所有其他项,只需检查最后一项。这应该比检查所有项目快得多

// sortedSourceArray is the source array, already sorted
NSMutableArray *newArray = [[NSMutableArray alloc] initWithObjects:[sortedSourceArray objectAtIndex:0]];
for (int i = 1; i < [sortedSourceArray count]; i++)
{
    if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
    {
        [newArray addObject:[tempArray objectAtIndex:i]];
    }
}


它应该工作得很好。如果
sortedSourceArray
包含
NSString
s、
NSNumber
s和/或
NSDate
s的组合,它可能会崩溃。

我知道这是一个老问题,但有一种更优雅的方法来删除中的重复项
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
if (![yourMutableArray containsObject:someValue])
{
   [yourMutableArray addObject:someValue];
}
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
for (int i=0; i<mainArray.count; i++) {
    if (listOfUsers.count==0) {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];

    }
   else if ([[listOfUsers valueForKey:@"name" ] containsObject:[[mainArray objectAtIndex:i] valueForKey:@"name"]])
    {  
       NSLog(@"Same object");
    }
    else
    {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];
    }
}
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
    if([datelistArray indexOfObject:data.date] == NSNotFound)
    [datelistArray addObject:data.date];
}