Objective-C: подсчитайте количество раз, когда объект встречается в массиве?

Мне нужно выполнить то, что я считаю основной функцией, но я не могу найти документацию о том, как это сделать. Пожалуйста, помогите!

Мне нужно подсчитать, сколько раз в массиве возникает определенный объект. Пример:

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

Как я могу перебирать массив и подсчитывать количество раз, когда он находит строку @ "Apple"?

Любая помощь приветствуется!

Ответ 1

Простой и конкретный ответ:

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

Еще одно решение, использующее блоки (рабочий пример):

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

Ответ 3

Используйте 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];

Ответ 4

Как сказал @bbum, используйте набор NSCounted. Существует инициализатор, который преобразует массив непосредственно в подсчитанный набор:

    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]; ...

Ответ 5

Просто наткнулся на этот довольно старый вопрос. Я бы рекомендовал использовать NSCountedSet:

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

Ответ 6

Я бы посоветовал вам поместить их в словарь (Objective C версия карты). Ключом к словарю является объект, а значение должно быть подсчетом. Конечно, это должен быть MutableDictionary. Если элемент не найден, добавьте его и установите для счетчика значение 1.

Ответ 7

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

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

    return count;
}

Ответ 8

Я проголосовал за Роба, но я хотел добавить код, который, я надеюсь, будет полезен.

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]);
}

Ответ 9

Если массив отсортирован, как в операторе проблемы, вам не нужно использовать словарь.

Вы можете найти количество уникальных элементов более эффективно, просто выполняя 1 линейную развертку и увеличивая счетчик, когда вы видите, что два последовательных элемента одинаковы.

Решение словаря - 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

Ответ 10

полный код со ссылкой на @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);
}

Спасибо.

Ответ 11

Если вы хотите, чтобы он был более общим, или вы хотите считать равные/разные объекты в массиве, попробуйте следующее:

Знак "!" count РАЗНЫЕ. Если вам нужны значения SAME, удалите "!"

  int count = 0;
  NSString *wordToCheck = [NSString string];
  for (NSString *str in myArray) {
    if( ![str isEqualToString:wordToCheck] ) {
      wordToCheck = str;
      count++;
    }
  }

надеюсь, что это поможет сообществу!

Я использовал его для добавления правильного количества разделов в uitableview!

Ответ 12

Вы можете сделать это,

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

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:array];
NSArray *uniqueStates = [[orderedSet set] allObjects];

NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array];
for(int i=0;i<[uniqueStates count];i++){
NSLog(@"%@  %d",[uniqueStates objectAtIndex:i], [countedSet countForObject: [uniqueStates objectAtIndex:i]]);
}

Результат выглядит так: A 1