2011-01-28 3 views
10

Мне нужно выполнить то, что я чувствую, это основная функция, но я не могу найти документацию о том, как это сделать. Пожалуйста помоги!Objective-C: подсчитывает количество случаев, когда объект встречается в массиве?

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

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

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

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

+1

Если это обычная операция, используйте 'NSCountedSet'. – bbum

ответ

13

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

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: Ответ Мартина Babacaev является довольно хорошо. Итерация выполняется быстрее с помощью блоков, но в этом конкретном случае с таким количеством элементов, я думаю, нет никакого очевидного выигрыша. Я хотел бы использовать, что, хотя :)

+2

Почему не просто 'вхождения + = [строка isEqualToString: @" Apple "];'? –

+0

Вы правы ... Я просто хотел сделать его более явным;) – nacho4d

+0

Извините, что навсегда принял этот ответ, но он выглядит как лучший! Благодаря! – EmphaticArmPump

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

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

    return count; 
} 
16

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

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

Привет, Мартин, этот ответ имеет посторонний заключительный параграф, который вызывает ошибку времени компиляции. Я пробовал редактировать в SO, но для их исправления требуется минимум 6 символов. Отличная линия! – rob5408

+0

Спасибо, Роб! Исправлено .. –

4

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

+1

Как уже упоминалось @Rob, проведите цикл по вашему массиву и создайте 'NSMutableDictionary' со значением, таким как' A', в качестве ключа, и счетчик, который был замечен как значение. – raidfive

2

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

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

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

Вы можете найти количество уникальных элементов более эффективно, просто выполняя 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 
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

Как @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], М [1], Е [1], A [1], В [3 ], X [2], C [1])

всего пунктов доступа:

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

Этот ответ очень хороший. Но можете ли вы получить массив с дублирующимися членами из NSCountedSet? (Например, для сохранения в файле plist). –

+0

Теперь, когда я думаю об этом, метод преобразования NSCountedSet <-> NSDictionary (ключи - это объекты в подсчитанном наборе, значения - это числа) было бы лучше, потому что plist был бы меньше. Я искал Google и ничего не нашел. Возможно, нам нужно реализовать такой метод вручную. –

0

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

Подпишите "!"Подсчитывать РАЗЛИЧНЫХ значения. Если вы хотите ЖЕ значения, удалить„!“

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

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

Я использовал его, чтобы добавить нужное количество секций в UITableView!

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

Спасибо.

0

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

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

В результате, как: 1

7

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

NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:array]; 
NSLog(@"Occurrences of Apple: %u", [countedSet countForObject:@"Apple"]); 
Смежные вопросы