2011-01-28 25 views
10

Ho bisogno di eseguire quello che sento è una funzione di base, ma non riesco a trovare alcuna documentazione su come farlo. Per favore aiuto!Objective-C: conta il numero di volte in cui un oggetto si verifica in una matrice?

Ho bisogno di contare quante volte un determinato oggetto si verifica in una matrice. Vedere l'esempio:

Come è possibile scorrere l'array e contare il numero di volte in cui trova la stringa @ "Apple"?

Qualsiasi aiuto è apprezzato!

+1

Se questa è un'operazione comune, utilizzare un 'NSCountedSet'. – bbum

risposta

13

una risposta semplice e specifico:

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: la risposta di Martin Babacaev è abbastanza buono. L'iterazione è più veloce con i blocchi, ma in questo caso specifico con così pochi elementi immagino che non ci sia un guadagno apparente. Userei che però :)

+2

perché non solo 'occorrenze + = [string isEqualToString: @" Apple "];'? –

+0

Hai ragione ... Volevo solo renderlo più esplicito;) – nacho4d

+0

Spiacente, ho impiegato per sempre questa risposta, ma sembra la migliore! Grazie! – 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

Un'altra soluzione, utilizzando blocchi (esempio di lavoro):

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

Ciao Martin, questa risposta ha un paren di chiusura estraneo che causa un errore di tempo di compilazione. Ho provato a modificare in SO, ma richiedono un minimo di 6 modifiche di carattere per inviare una correzione. Grande linea però! – rob5408

+0

Grazie Rob! Risolto .. –

4

vorrei incoraggiarvi a metterli in un dizionario (Obiettivo versione C di una mappa) . La chiave del dizionario è l'oggetto e il valore dovrebbe essere il conteggio. Dovrebbe essere un MutableDictionary ovviamente. Se l'articolo non viene trovato, aggiungilo e imposta il conteggio a 1.

+1

Come menzionato da @Rob, esegui un ciclo attraverso l'array e crea un 'NSMutableDictionary' con il valore, ad esempio' A', come chiave e il conteggio che chiave è stato visto come valore. – raidfive

2

Ho risposto alla risposta di Rob, ma volevo aggiungere del codice che spero possa essere di aiuto.

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

Se la matrice è ordinata come nell'istruzione problema, non è necessario utilizzare un dizionario.

È possibile trovare il numero di elementi unici in modo più efficiente semplicemente eseguendo 1 scansione lineare e incrementando un contatore quando si vedono 2 elementi consecutivi uguali.

La soluzione del dizionario è O (nlog (n)), mentre la soluzione lineare è O (n).

Ecco alcuni pseudo-codice per la soluzione lineare:

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

Utilizzare un NSCountedSet; sarà più veloce di un dizionario ed è progettato per risolvere esattamente questo problema.

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

Come detto @bbum, utilizzare un set NSCounted. C'è una plafoniera inizializzatore convertirà un array direttamente in un set contati:

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 uscita: (D [1], M [1], E [1], A [1], B [3 ], X [2], C [1])

soli elementi di accesso:

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

Questa risposta è molto buona. Ma puoi ottenere l'array con membri duplicati da NSCountedSet? (Ad esempio, per archiviarlo in un file plist). –

+0

Ora che ci penso, un metodo per convertire NSCountedSet <-> NSDictionary (le chiavi sono oggetti nel set contato, i valori sono i conteggi) sarebbe meglio, perché il plist sarebbe più piccolo. Ho cercato su google, e non sono riuscito a trovare nulla. Probabilmente abbiamo bisogno di implementare un tale metodo manualmente. –

0

Se lo vuoi più generica, o se si vuole contare uguali/diversi oggetti in array, provate questo:

Segno "!"Contare DIVERSI valori. Se si desidera STESSI valori, rimuovere '!'

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

speranza che questo aiuti la comunità!

ho usato per aggiungere corretto numero di sezioni in UITableView!

2

il codice completo con riferimento alla @bbum e @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); 
} 

Grazie.

0

È possibile farlo in questo modo,

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

Il risultato è simile: A 1

7

appena incontrato questa bella vecchia domanda. Mi consiglia di utilizzare un NSCountedSet:

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