NSString
从NSMutableArray
Objective-C中删除重复值()的最佳方法?
这是最简单正确的方法吗?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
NSString
从NSMutableArray
Objective-C中删除重复值()的最佳方法?
这是最简单正确的方法吗?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Answers:
NSSet
如果您不担心对象的顺序,那么您的方法是最好的;但是,如果您不担心对象的顺序,那么您的方法又为什么又不存储在对象中NSSet
呢?
我在2009年写下了答案;在2011年,Apple添加NSOrderedSet
了iOS 5和Mac OS X 10.7。原来是一种算法,现在只有两行代码:
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];
[NSOrderedSet orderedSetWithArray:array];
即可,然后可以通过array = [orderedSet allObjects];
或直接使用NSOrderedSet
s而不是NSArray
首先返回数组。
[orderedSet allObjects]
为[orderedSet array]
!
NSArray
并且应该创建temp NSMutableArray
。在您的示例中,反之亦然
NSSet
)或@Simon Whitaker 链接防止在添加重复项值之前这样做是有效的方法吗?
我知道这是一个古老的问题,但是NSArray
如果您不关心订单,可以使用一种更优雅的方法删除重复项。
如果我们使用键值编码中的对象运算符,则可以执行以下操作:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
正如AnthoPak还指出的那样,可以根据属性删除重复项。一个例子是:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
通过自定义对象数组的属性删除重复项一样使用。例如@distinctUnionOfObjects.name
是的,使用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的示例中使用)都无法很好地用于大型数组。这些检查的运行时间为O(N),这意味着如果将原始数组的大小加倍,则每次检查将花费两倍的时间。由于您要对数组中的每个对象进行检查,因此您还将运行更多这些更昂贵的检查。整个算法(我的和Jim的算法)都在O(N 2)时间内运行,随着原始数组的增长,该算法很快变得昂贵。
为了将时间减少到O(N),您可以使用a 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)性能。)
那么该怎么办?这取决于实际情况。如果您的阵列很大,并且只期望少量的重复项,那么就地重复数据删除就可以很好地工作,并且省去了构建重复阵列的麻烦。如果您希望在阵列中有很多重复项,那么建立一个单独的,重复数据删除的阵列可能是最好的方法。这里的要点是big-O表示法仅描述算法的特征,而不能明确地告诉您哪种方法最适合给定的情况。
如果您的目标是iOS 5+(涵盖了整个iOS世界),请最好使用NSOrderedSet
。它将删除重复项并保留您的订单NSArray
。
做就是了
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
您现在可以将其转换回唯一的NSArray
NSArray *uniqueArray = orderedSet.array;
或只使用orderedSet,因为它具有与NSArray等相同的方法objectAtIndex:
,firstObject
等等。
的会员资格检查比contains
上的会员检查更快NSOrderedSet
NSArray
有关更多信息,请参阅NSOrderedSet参考。
在OS X v10.7和更高版本中可用。
如果您担心订单,正确的做法
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];
以下是按顺序从NSArray中删除重复值的代码。
需要订单
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);
在这里,我从mainArray中删除了重复的名称值,并将结果存储在NSMutableArray(listOfUsers)中
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]];
}
}
请注意,如果您有一个已排序的数组,则不需要检查数组中的所有其他项目,只需检查最后一项即可。这应该比检查所有项目快得多。
// 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]];
}
}
看来NSOrderedSet
,建议的答案也需要更少的代码,但是如果NSOrderedSet
由于某种原因您不能使用an ,并且您有一个排序数组,那么我相信我的解决方案将是最快的。我不确定将其与NSOrderedSet
解决方案的速度进行比较。另请注意,我的代码正在与核对isEqualToString:
,因此同一字母序列在中不会出现多次newArray
。我不确定NSOrderedSet
解决方案是否将基于值或基于内存位置删除重复项。
我的示例假定sortedSourceArray
仅包含NSString
s,仅NSMutableString
s或两者的混合。如果sortedSourceArray
只包含NSNumber
或NSDate
,则可以替换
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
与
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
它应该可以正常工作。如果sortedSourceArray
包含NSString
s,NSNumber
s和/或NSDate
s的混合,则可能会崩溃。
您可以尝试一种更简单的方法来尝试在数组中添加对象之前不添加重复的值:-
//假设分配了mutableArray并初始化并包含一些值
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
从Objective-C中的NSMutableArray删除重复的值
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
这是从NSMutable Array中删除重复值的代码。。它将为您工作。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
只需使用以下简单代码:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
因为nsset不允许重复值,并且所有对象都返回一个数组
NSOrderedSet
insteed的NSSet
。