NSArray:删除具有重复属性的对象

时间:2011-09-20 21:08:25

标签: objective-c ios nsarray

我有一个包含一些自定义对象的NSMutableArray。其中两个对象具有相同的属性,如标题和作者。我想删除重复的对象并离开另一个。

Asset *asset;
NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];

// First
asset = [[Asset alloc] init];
asset.title = @"Developer";
asset.author = @"John Smith";
[items addObject:asset];
[asset release];

// Second
asset = [[Asset alloc] init];
asset.title = @"Writer";
asset.author = @"Steve Johnson";
[items addObject:asset];
[asset release];

// Third
asset = [[Asset alloc] init];
asset.title = @"Developer";
asset.author = @"John Smith";
[items addObject:asset];
[asset release];

由于它们不是同一个对象,但只有重复的属性,我该如何删除副本?

5 个答案:

答案 0 :(得分:13)

你可以创建一个HashSet,当你循环时,你可以将“title + author”连接集添加到HashSet(NSMutableSet)。当您到达每个项目时,如果HashSet包含您的密钥,请删除它或不复制(删除或创建没有重复的副​​本)。

这使它成为n阶(1循环)

这是NSMutableSet类:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableSet_Class/Reference/NSMutableSet.html#//apple_ref/occ/cl/NSMutableSet

使用代码进行编辑:

代码的核心是一个循环。

void print(NSMutableArray *assets)
{
    for (Asset *asset in assets)
    {
        NSLog(@"%@/%@", [asset title], [asset author]);
    }
}

int main (int argc, const char * argv[])
{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    //
    // Create the initial data set
    //
    Asset *asset;
    NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];

    // First
    asset = [[Asset alloc] init];
    asset.title = @"Developer";
    asset.author = @"John Smith";
    [items addObject:asset];
    [asset release];

    // Second
    asset = [[Asset alloc] init];
    asset.title = @"Writer";
    asset.author = @"Steve Johnson";
    [items addObject:asset];
    [asset release];

    // Third
    asset = [[Asset alloc] init];
    asset.title = @"Developer";
    asset.author = @"John Smith";
    [items addObject:asset];
    [asset release];

    NSLog(@"****Original****");
    print(items);

    //
    // filter the data set in one pass
    //
    NSMutableSet *lookup = [[NSMutableSet alloc] init];
    for (int index = 0; index < [items count]; index++)
    {
        Asset *curr = [items objectAtIndex:index];
        NSString *identifier = [NSString stringWithFormat:@"%@/%@", [curr title], [curr author]];

        // this is very fast constant time lookup in a hash table
        if ([lookup containsObject:identifier])
        {
            NSLog(@"item already exists.  removing: %@ at index %d", identifier, index);
            [items removeObjectAtIndex:index];
        }
        else
        {
            NSLog(@"distinct item.  keeping %@ at index %d", identifier, index);
            [lookup addObject:identifier];
        }
    }

    NSLog(@"****Filtered****");
    print(items);

    [pool drain];
    return 0;
}

这是输出:

Craplet[11991:707] ****Original****
Craplet[11991:707] Developer/John Smith
Craplet[11991:707] Writer/Steve Johnson
Craplet[11991:707] Developer/John Smith
Craplet[11991:707] distinct item.  keeping Developer/John Smith at index 0
Craplet[11991:707] distinct item.  keeping Writer/Steve Johnson at index 1
Craplet[11991:707] item already exists.  removing: Developer/John Smith at index 2
Craplet[11991:707] ****Filtered****
Craplet[11991:707] Developer/John Smith
Craplet[11991:707] Writer/Steve Johnson

答案 1 :(得分:4)

您可以使用NSSet的唯一性从原始数组中获取不同的项目。如果您拥有Assest的源代码,则需要覆盖isEqual:类的hashAsset方法。

@interface Asset : NSObject
@property(copy) NSString *title, *author;
@end

@implementation Asset
@synthesize title, author;

-(NSUInteger)hash
{
    NSUInteger prime = 31;
    NSUInteger result = 1;

    result = prime * result + [self.title hash];
    result = prime * result + [self.author hash];

    return result;
}

-(BOOL)isEqual:(id)object
{
    return [self.title isEqualToString:[object title]] && 
    [self.author isEqualToString:[object author]];
}

- (void)dealloc {
    [title release];
    [author release];
    [super dealloc];
}

@end

然后实施:

Asset *asset;
NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];

// First
asset = [[Asset alloc] init];
asset.title = @"Developer";
asset.author = @"John Smith";
[items addObject:asset];
[asset release];

// Second
asset = [[Asset alloc] init];
asset.title = @"Writer";
asset.author = @"Steve Johnson";
[items addObject:asset];
[asset release];

// Third
asset = [[Asset alloc] init];
asset.title = @"Developer";
asset.author = @"John Smith";
[items addObject:asset];
[asset release];

NSLog(@"Items: %@", items);

NSSet *distinctItems = [NSSet setWithArray:items];

NSLog(@"Distinct: %@", distinctItems);

如果你最后需要一个数组,你可以调用[distinctItems allObjects]

答案 2 :(得分:2)

首先,我会覆盖资产的isEqual:方法,如下所示:

-(BOOL)isEqual:(Asset *)otherAsset {
    return [self.title isEqual:otherAsset.title] && [self.author isEqual:otherAsset.author];
}

然后,如果你想避免首先在数组中放置重复项:

NSUInteger idx = [items indexOfObject:asset];  // tests objects for equality using isEqual:
if (idx == NSNotFound) [items addObject:asset];

如果数组已包含重复项,那么找到它们的任何算法的运行时间都比线性更差,但我认为创建一个新数组并且只添加上面的唯一元素是最好的算法。像这样:

NSMutableArray *itemsWithUniqueElements = [NSMutableArray arrayWithCapacity:[items count]];

for (Asset *anAsset in items) {
    if ([items indexOfObject:anAsset] == NSNotFound)
        [itemsWithUniqueElements addObject:anAsset];
}

[items release];
items = [itemsWithUniqueElements retain];

在最坏的情况下(所有元素都是唯一的),迭代次数为:

1 + 2 + 3 + ... + n =  n * (n+1) / 2

哪个仍然是O(n ^ 2),但比@Justin Meiners的算法略胜一筹。没有冒犯的意思! :)

答案 3 :(得分:0)

这是你可以做到的一种方式 :

NSMutableArray* toRemove = [NSMutableArray array];

    for (Asset* asset1 in items)
    {
        for (Asset* asset2 in items)
        {
            if (asset1 != asset2)
            {
                if ([asset1.title isEqualToString:asset2.title] && [asset1.author isEqualToString:asset2.author])
                {
                    [toRemove addObject:asset2];
                }
            }
        }
    }

    for (Asset* deleted in toRemove)
    {
        [items removeObject:toRemove];
    }

答案 4 :(得分:0)

如果您希望自定义NSObject子类的名称相等,则可以实现isEqual:hash。这将允许您将对象添加到NSSet / NSMutableSet(一组不同的对象)。

然后,您可以使用NSArray的{​​{1}}方法轻松创建排序NSSet

MikeAsh写了一篇关于实现自定义平等的非常可靠的文章:Friday Q&A 2010-06-18: Implementing Equality and Hashing