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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1025674/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:03:35  来源:igfitidea点击:

The best way to remove duplicate values from NSMutableArray in Objective-C?

iosobjective-cnsmutablearray

提问by Teo Choong Ping

The best way to remove duplicate values (NSString) from NSMutableArrayin Objective-C?

NSStringNSMutableArrayObjective-C 中删除重复值 ( )的最佳方法?

Is this the easiest and right way to do it?

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

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

回答by Jim Puls

Your NSSetapproach is the best if you're not worried about the order of the objects, but then again, if you're not worried about the order, then why aren't you storing them in an NSSetto begin with?

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

I wrote the answer below in 2009; in 2011, Apple added NSOrderedSetto iOS 5 and Mac OS X 10.7. What had been an algorithm is now two lines of code:

我在 2009 年写了下面的答案;2011 年,Apple 添加NSOrderedSet到 iOS 5 和 Mac OS X 10.7。曾经的算法现在是两行代码:

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


If you are worried about the order and you're running on iOS 4 or earlier, loop over a copy of the 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];

回答by Tiago Almeida

I know this is an old question, but there is a more elegant way to remove duplicates in a NSArrayif you don't care about the order.

我知道这是一个老问题,但是NSArray如果您不关心 order,则有一种更优雅的方法可以删除 a 中的重复项。

If we use Object Operators from Key Value Codingwe can do this:

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

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

As AnthoPakalso noted it is possible to remove duplicates based on a property. An example would be: @distinctUnionOfObjects.name

正如AnthoPak还指出的那样,可以根据属性删除重复项。一个例子是:@distinctUnionOfObjects.name

回答by Simon Whitaker

Yes, using NSSet is a sensible approach.

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

To add to Jim Puls' answer, here's an alternative approach to stripping duplicates while retaining order:

要添加到 Jim Puls 的回答中,这里有一种在保留顺序的同时去除重复项的替代方法:

// Initialise a new, empty mutable array 
NSMutableArray *unique = [NSMutableArray array];

for (id obj in originalArray) {
    if (![unique containsObject:obj]) {
        [unique addObject:obj];
    }
}

It's essentially the same approach as Jim's but copies unique items to a fresh mutable array rather than deleting duplicates from the original. This makes it slightly more memory efficient in the case of a large array with lots of duplicates (no need to make a copy of the entire array), and is in my opinion a little more readable.

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

Note that in either case, checking to see if an item is already included in the target array (using containsObject:in my example, or indexOfObject:inRange:in Jim's) doesn't scale well for large arrays. Those checks run in O(N) time, meaning that if you double the size of the original array then each checkwill take twice as long to run. Since you're doing the check for each object in the array, you'll also be running more of those more expensive checks. The overall algorithm (both mine and Jim's) runs in O(N2) time, which gets expensive quickly as the original array grows.

请注意,无论哪种情况,检查某个项目是否已包含在目标数组中(containsObject:在我的示例中或indexOfObject:inRange:在 Jim 的示例中使用)对于大型数组都不能很好地扩展。这些检查在 O(N) 时间内运行,这意味着如果将原始数组的大小增加一倍,那么每次检查将花费两倍的时间来运行。由于您正在对数组中的每个对象进行检查,因此您还将运行更多更昂贵的检查。整个算法(我的和 Jim 的)在 O(N 2) 时间内运行,随着原始数组的增长,这会很快变得昂贵。

To get that down to O(N) time you could use a NSMutableSetto store a record of items already added to the new array, since NSSet lookups are O(1) rather than O(N). In other words, checking to see whether an element is a member of an NSSet takes the same time regardless of how many elements are in the set.

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

Code using this approach would look something like this:

使用这种方法的代码看起来像这样:

NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];

for (id obj in originalArray) {
    if (![seen containsObject:obj]) {
        [unique addObject:obj];
        [seen addObject:obj];
    }
}

This still seems a little wasteful though; we're still generating a new array when the question made clear that the original array is mutable, so we should be able to de-dupe it in place and save some memory. Something like this:

不过,这似乎仍然有点浪费;当问题明确表明原始数组是可变的时,我们仍在生成一个新数组,因此我们应该能够就地删除重复数据并节省一些内存。像这样的东西:

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++;
    }
}


UPDATE: Yuri Niyazov pointed outthat my last answer actually runs in O(N2) because removeObjectAtIndex:probably runs in O(N) time.

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

(He says "probably" because we don't know for sure how it's implemented; but one possible implementation is that after deleting the object at index X the method then loops through every element from index X+1 to the last object in the array, moving them to the previous index. If that's the case then that is indeed O(N) performance.)

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

So, what to do? It depends on the situation. If you've got a large array and you're only expecting a small number of duplicates then the in-place de-duplication will work just fine and save you having to build up a duplicate array. If you've got an array where you're expecting lots of duplicates then building up a separate, de-duped array is probably the best approach. The take-away here is that big-O notation only describes the characteristics of an algorithm, it won't tell you definitively which is best for any given circumstance.

那么该怎么办?这取决于实际情况。如果您有一个大型数组并且您只期望少量重复,那么就地重复数据删除将工作得很好,并且您不必构建重复数组。如果您有一个预计会有大量重复的数组,那么构建一个单独的、重复数据删除的数组可能是最好的方法。这里的要点是,大 O 符号只描述了算法的特征,它不会明确地告诉你哪个最适合任何给定的情况。

回答by lukaswelte

If you are targeting iOS 5+ (what covers the whole iOS world), best use NSOrderedSet. It removes duplicates and retains the order of your NSArray.

如果您的目标是 iOS 5+(涵盖整个 iOS 世界),最好使用NSOrderedSet. 它删除重复项并保留您的NSArray.

Just do

做就是了

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];

You can now convert it back to a unique NSArray

您现在可以将其转换回唯一的 NSArray

NSArray *uniqueArray = orderedSet.array;

Or just use the orderedSet because it has the same methods like an NSArray like objectAtIndex:, firstObjectand so on.

或者只是使用orderedSet,因为它具有与NSArray 一样的方法objectAtIndex:firstObject等等。

A membership check with containsis even faster on the NSOrderedSetthan it would be on an NSArray

以A成员资格检查contains还要快上NSOrderedSet那将是比上NSArray

For more checkout the NSOrderedSet Reference

如需更多信息,请查看 NSOrderedSet 参考

回答by Sultania

Available in OS X v10.7 and later.

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

If you are worried about the order,right way to do

如果您担心订单,正确的做法

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

Here is the code of removing duplicates values from NSArray in Order.

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

回答by Mike

need order

需要订单

NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);

or don't need order

或者不需要订单

NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);

回答by Bibin Joseph

Here i removed duplicate name values from mainArray and store result in NSMutableArray(listOfUsers)

在这里,我从 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]];
    }
}

回答by Peter

There's a KVC Object Operator that offers a more elegant solution uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];Here's an NSArray category.

有一个 KVC Object Operator 提供了一个更优雅的解决方案uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];这是一个NSArray 类别

回答by Hussain Shabbir

One more simple way you can try out which will not add duplicate Value before adding object in array:-

您可以尝试一种更简单的方法,在将对象添加到数组之前不会添加重复的值:-

//Assume mutableArray is allocated and initialize and contains some value

//假设mutableArray已分配并初始化并包含一些值

if (![yourMutableArray containsObject:someValue])
{
   [yourMutableArray addObject:someValue];
}

回答by Arvind Patel

Remove duplicate values from NSMutableArray in Objective-C

从 Objective-C 中的 NSMutableArray 中删除重复值

NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
    if([datelistArray indexOfObject:data.date] == NSNotFound)
    [datelistArray addObject:data.date];
}