在NSArray中分组重复项

5

我有一个包含自定义对象的NSArray,例如:

[A, A, B, C, A, D, E, B, D]

最好的方法是将这些项目分组,使最终结果类似于以下内容:

A: 3
B: 2
C: 1
D: 2
E: 1

请注意,这些重复项都是具有相同属性的不同实例,但我已经为此覆盖了isEqual:方法。

你想要的结果更像是一个字典而不是一个数组,你想要与字母相关联的计数吗? - Chris Wagner
@ChrisWagner 是的,但它们不是字母。它们是自定义对象。 - pixelfreak
2个回答

8
最简单的方法可能是使用一个NSCountedSet。您可以使用[NSCountedSet setWithArray:myArray]来生成一个计数集合,然后您可以遍历集合的内容以找出集合中每个对象的计数。请注意,它不会被排序。
还要注意,为了使其工作,您需要提供一个明智的-hash实现,因为您只覆盖了-isEqual:。如果您需要结果的排序列表,还需要覆盖-compare:
这是一个快速的方法,它接受您的数组并打印每个元素的计数,已经排序:
void printCountOfElementsInArray(NSArray *ary) {
    NSCountedSet *set = [NSCountedSet setWithArray:ary];
    NSArray *objs = [[set allObjects] sortedArrayUsingSelector:@selector(compare:)];
    for (id obj in objs) {
        NSLog(@"%@: %d", obj, [set countForObject:obj]);
    }
}

谢谢,我对散列(hash)不熟悉。你能指点我如何重写它吗?还有为什么我需要重写 hash 呢?我以为只重写 isEqual 就足够了... - pixelfreak
@pixelfreak:关于-hash的唯一必须成立的事情是两个相等的对象(即从-isEqual:返回YES的对象)必须从-hash返回相同的值。然而,反之不一定成立。从-hash返回相同值的两个对象不一定相等。这意味着你可以将此方法实现为- (NSUInteger)hash { return 1; }。如果你想的话。但是,这将导致非常低效的字典/集合。哈希函数的维基百科页面有有用的信息。 - Lily Ballard
@pixelfreak:作为参考,我相信NSObject-hash的默认实现只是返回对象指针。这意味着如果你实现了自定义的-isEqual:(并且希望将对象用作字典的键或集合的一部分),则必须重写它。 - Lily Ballard
1
@pixelfreak:如果我的对象由其他具有良好“-hash”实现的对象组成,则我倾向于将它们的哈希值简单地进行异或运算。但是,如果你有C语言基本类型(例如int),那么你提供的链接是很好的。 - Lily Ballard
最后一个问题,我假设如果我修改已经添加到NSCountedSet中的任何对象,它将不能按预期工作? - pixelfreak
显示剩余5条评论

7
使用 NSCountedSet 类。
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:myArray];
NSUInteger countForA = [countedSet countForObject:@"A"];
NSLog(@"A: %u", countForA);

抱歉,我猜这个例子不太好。那些不是字母,它们是自定义对象。所以@Kevin的答案更接近。 - pixelfreak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接