Objective-C:计算数组中对象出现的次数?

13

我需要执行一个我认为是基本的功能,但是找不到任何关于如何执行它的文档。请帮忙!

我需要统计一个特定对象在数组中出现的次数。请参考以下示例:

array = NSArray arrayWithObjects:@"Apple", @"Banana", @"Cantaloupe", @"Apple", @"DragonFruit", @"Eggplant", @"Apple", @"Apple", @"Guava",nil]retain];

我如何遍历数组并计算找到字符串@"Apple"的次数?

感谢您的帮助!


1
如果这是一个常见的操作,请使用NSCountedSet - bbum
12个回答

22

另外一种解决方案,使用代码块(可工作示例):

NSInteger occurrences = [[array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {return [obj isEqual:@"Apple"];}] count];
NSLog(@"%d",occurrences);

嗨,马丁,这个答案有一个多余的闭合括号,导致编译时出错。我尝试在SO中进行编辑,但他们要求至少编辑6个字符才能提交修复。不过这是一行很棒的代码! - rob5408

17

正如 @bbum 所说,使用 NSCounted set。有一个初始化程序可以直接将数组转换为计数集:

    NSArray *array = [[NSArray alloc] initWithObjects:@"A", @"B", @"X", @"B", @"C", @"D", @"B", @"E", @"M", @"X", nil];
    NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array];
    NSLog(@"%@", countedSet);

NSLog输出: (D [1], M [1], E [1], A [1], B [3], X [2], C [1])

只需访问项目:

count = [countedSet countForObject: anObj]; ...

这个回答非常好。但是,你能否从NSCountedSet中获取包含重复成员的数组呢?(例如,用于将其存储在plist文件中)。 - Ricardo Sanchez-Saez
现在我想起来,编写一个将NSCountedSet <-> NSDictionary(键是计数集中的对象,值是计数)相互转换的方法会更好,因为这样生成的plist文件会更小。我已经搜索了一下,但没有找到相关内容。可能我们需要手动实现这样的方法。 - Ricardo Sanchez-Saez

15

使用一个NSCountedSet;它比字典更快,并且专门设计解决这个问题。

NSCountedSet *cs = [NSCountedSet new];
for(id anObj in someArray) 
    [cs addObject: anObj];

// then, you can access counts like this:
.... count = [cs countForObject: anObj]; ...

[cs release];

15

一个简单而具体的回答:

int occurrences = 0;
for(NSString *string in array){
    occurrences += ([string isEqualToString:@"Apple"]?1:0); //certain object is @"Apple"
}
NSLog(@"number of occurences %d", occurrences);

PS:马丁·巴巴凯夫的答案也很不错。使用块可以加快迭代速度,但在这种具有如此少元素的情况下,我猜没有明显的增益。不过我还是会使用它 :)


2
为什么不直接使用 occurrences += [string isEqualToString:@"Apple"]; 呢? - Martin Babacaev
抱歉我花了很长时间才接受这个答案,但它看起来是最好的!谢谢! - EmphaticArmPump

8

我刚看到这个比较旧的问题。我建议使用一个NSCountedSet

NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array];
NSLog(@"Occurrences of Apple: %u", [countedSet countForObject:@"Apple"]);

4

我建议您将它们放入一个字典中(即Objective C的映射版本)。字典的键是对象,值应该是计数。当然,它应该是一个可变字典。如果未找到该项,请添加它并将计数设置为1。


1
如@Rob所提到的那样,循环遍历您的数组并使用值(例如A)作为键,使用该键已被见过的计数作为值来构建一个NSMutableDictionary - raidfive

3
- (int) numberOfOccurrencesForString:(NSString*)needle inArray:(NSArray*)haystack {
    int count = 0;

    for(NSString *str in haystack) {
        if([str isEqualToString:needle]) {
            count++;
        }
    }

    return count;
}

2

我点赞了Rob的回答,但我想添加一些代码,希望能对你有所帮助。

NSArray *array = [[NSArray alloc] initWithObjects:@"A", @"B", @"B", @"B", @"C", @"D", @"E", @"M", @"X", @"X", nil];

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
for(int i=0; i < [array count]; i++) {
    NSString *s = [array objectAtIndex:i];
    if (![dictionary objectForKey:s]) {
        [dictionary setObject:[NSNumber numberWithInt:1] forKey:s];
    } else {
        [dictionary setObject:[NSNumber numberWithInt:[dictionary objectForKey:s] intValue]+1 forKey:s];
    }
}

for(NSString *k in [dictionary keyEnumerator]) {
    NSNumber *number = [dictionary objectForKey:k];
    NSLog(@"Value of %@:%d", k, [number intValue]);
}

2

如果数组按照问题陈述中的方式排序,则无需使用字典。

你可以通过一次线性扫描并在看到两个连续元素相同时将计数器递增来更有效地找到唯一元素的数量。

字典解决方案的时间复杂度为O(nlog(n)), 而线性解决方案的时间复杂度为O(n)。

以下是线性解决方案的伪代码:

array = A,B,B,B,B,C,C,D,E,M,X,X #original array
array = array + -1 # array with a dummy sentinel value to avoid testing corner cases.

# Start with the first element. You want to add some error checking here if array is empty.
last = array[0]
count = 1 # you have seen 1 element 'last' so far in the array.
for e in array[1..]: # go through all the elements starting from the 2nd one onwards
  if e != last: # if you see a new element then reset the count
    print "There are " + count + " " + last elements
    count = 1 # unique element count
  else:
    count += 1
  last = e

2

参考@bbum和@Zaph的完整代码。

NSArray *myArray = [[NSArray alloc] initWithObjects:@"A", @"B", @"X", @"B", @"C", @"D", @"B", @"E", @"M", @"X", nil];
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:myArray];

for (NSString *item in countedSet) {

    int count = [countedSet countForObject: item];
    NSLog(@"the String ' %@ ' appears %d times in the array",item,count);
}

谢谢你。

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