2011-01-28 11 views
10

Necesito realizar lo que creo que es una función básica, pero no encuentro ninguna documentación sobre cómo hacerlo. ¡Por favor ayuda!Objetivo-C: ¿Cuenta el número de veces que un objeto ocurre en una matriz?

Necesito contar cuántas veces ocurre un determinado objeto en una matriz. Ver ejemplo:

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

¿Cómo puedo iterar a través de la matriz y contar el número de veces que encuentra la cadena @ "Apple"?

¡Se agradece cualquier ayuda!

+1

Si esta es una operación común, utilizar un 'NSCountedSet'. – bbum

Respuesta

13

una respuesta simple y específico:

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

PD: La respuesta de Martin Babacaev es bastante bueno también. La iteración es más rápida con bloques, pero en este caso específico con tan pocos elementos supongo que no hay ganancia aparente. Me gustaría utilizar que aunque :)

+2

¿por qué no solo 'occurrences + = [string isEqualToString: @" Apple "];'? –

+0

Tienes razón ... Solo quería hacerlo más explícito;) – nacho4d

+0

Lo siento, me tomó mucho tiempo aceptar esta respuesta, pero parece ser la mejor. ¡Gracias! – 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

Uno más solución, utilizando bloques (ejemplo de trabajo):

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

Hola Martin, esta respuesta tiene un par adicional de cierre que provoca un error de tiempo de compilación. Intenté editar en SO, pero requieren un mínimo de 6 ediciones de caracteres para enviar una solución. ¡Excelente línea! – rob5408

+0

Gracias Rob! Corregido .. –

4

les animo a ponerlas en un diccionario (versión Objetivo de C de un mapa) . La clave del diccionario es el objeto y el valor debe ser el recuento. Debería ser un MutableDictionary por supuesto. Si el artículo no se encuentra, agréguelo y establezca el recuento en 1.

+1

Como lo menciona @Rob, recorra su matriz y construya un 'NSMutableDictionary' con el valor, como' A', como la clave, y el recuento de esa clave se ha visto como el valor. – raidfive

2

Elegí la respuesta de Rob, pero quería agregar un código que espero sea de alguna ayuda.

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

Si la matriz está ordenada como en el enunciado del problema, entonces no necesita utilizar un diccionario.

Puede encontrar la cantidad de elementos únicos de manera más eficiente simplemente haciendo 1 barrido lineal e incrementando un contador cuando vea que 2 elementos consecutivos son iguales.

La solución del diccionario es O (nlog (n)), mientras que la solución lineal es O (n).

He aquí algunos pseudo-código para la solución lineal:

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

Utilice un NSCountedSet; será más rápido que un diccionario y está diseñado para resolver exactamente ese 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

Como dijo @bbum, use un conjunto NSCounted. Hay un thet inicializador convertirá una matriz directamente en un conjunto contado:

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

a sólo elementos de acceso:

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

Esta respuesta es muy buena. Pero, ¿puede obtener la matriz con miembros duplicados de NSCountedSet? (Por ejemplo, para almacenarlo en un archivo plist). –

+0

Ahora que lo pienso, un método para convertir NSCountedSet <-> NSDictionary (las claves son objetos en el conjunto contado, los valores son los recuentos) sería mejor, porque el plist sería más pequeño. He estado buscando en Google y no he podido encontrar nada. Probablemente necesitamos implementar dicho método manualmente. –

0

Si desea más genérico, o que desea contar iguales/diferentes objetos en serie, intente esto:

Sign "!"Contar DIFERENTES valores. Si desea MISMAS valores, quite '!'

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

esperanza esto ayuda a la comunidad!

lo he usado para añadir número correcto de las secciones UITableView!

2

el código completo con referencia a @bbum y @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); 
} 

Gracias.

0

Puede hacerlo de esta manera,

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

El resultado es como: Un 1

7

encontré con este bonito vieja cuestión. Me gustaría recomendar el uso de un NSCountedSet:

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