2010-12-28 14 views
14

Esto se siente como una pregunta tonta porque me parece que mi caso de uso debe ser bastante común.NSIndexSet "-indexAtIndex:"?

Digamos que quiero representar un conjunto escaso de índices con un NSIndexSet (que es por supuesto para qué sirve). Puedo usar -firstIndex para obtener la más baja y -lastIndex para la más alta, pero ¿cuál es la manera canónica de obtener un solo índice arbitrario en el medio, dado su "índice"? Los documentos me han dejado claro.

E.g. si tengo un índice establecido con los índices {0, 5, 8, 10, 12, 28}, y quiero decir "dame el cuarto índice" y esperaría recuperar 10 (o 12 supongo que sobre si cuento el zeroth, pero no entremos en eso, ya sabes a qué me refiero).

Tenga en cuenta que no estoy haciendo "enumeración" en todo el conjunto de índices. En un punto dado en el tiempo solo quiero saber cuál es el n-ésimo índice en el conjunto por orden numérico.

Quizás mi estructura de datos sea incorrecta (los "conjuntos" generalmente no están diseñados para tal acceso ordenado), pero parece que no hay ningún NSIndexArray del que hablar.

¿Me falta algo obvio?

Gracias!

+2

Por qué no usar NSArray? –

+0

Tal vez pueda solucionar esta respuesta: http://stackoverflow.com/questions/905828/get-nsindexset-from-nsarray – chuckSaldana

+1

@Neilvert: puedo terminar haciéndolo, pero encajonar los números enteros en NSNumbers parecía excesivo cuando ¡la estructura de datos para contener índices parecía tan conveniente! :) –

Respuesta

4

Creo que NSIndexSet almacena sus índices utilizando rangos, por lo que no hay necesariamente una manera rápida de devolver el índice nth. Se podría enumerar manteniendo un contador hasta que el contador llegue a su índice de destino:

NSUInteger index = [indexSet firstIndex]; 

for (NSUInteger i = 0, target = 4; i < target; i++) 
    index = [indexSet indexGreaterThanIndex:index]; 

que debe darle el cuarto índice. Incluso se puede añadir el método como un método categoría si desea:

- (NSUInteger)indexAtIndex:(NSUInteger)anIndex 
{ 
    if (anIndex >= [self count]) 
     return NSNotFound; 

    NSUInteger index = [indexSet firstIndex]; 
    for (NSUInteger i = 0; i < anIndex; i++) 
     index = [self indexGreaterThanIndex:index]; 
    return index; 
} 

Pero, como usted ha dicho, esto puede no ser la mejor estructura de datos a utilizar por lo que considerar que más antes de ir con algo como esto.

+0

Sí, parece que no me faltaba algo obvio. Desafortunadamente, si almacena los índices como rangos internos, podría exponer indexAtIndex más eficientemente de lo que puedo hacerlo en una categoría, pero señalado. Gracias. –

6

NSIndexSet no está diseñado para ese tipo de acceso. Por lo general, enumerar a través de los índices en un conjunto de este modo:

NSUInteger idx = [theSet indexGreaterThanOrEqualToIndex: 0]; 
while (idx != NSNotFound) { 
    // idx equals the next index in the set. 
    idx = [theSet indexGreaterThanIndex: idx]; 
} 

@Richard señala este bucle for es más simple:

for (NSUInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i]) { 
    // i equals the next index in the set. 
} 

Hay algunos métodos basados ​​en bloques que son nuevas para NSIndexSet como de Mac OS X 10.6/iOS 4.0, pero aún no los he revisado.

Debe ser trivial modificar el ejemplo anterior para mantener un recuento de índices en ejecución y detenerse cuando alcanza el cuarto índice en el conjunto. ;)

+0

que prácticamente lo dice todo, aunque habría escrito el ejemplo de código como un ciclo for: 'for (NSUInteger i = [indexSet firstIndex]; i! = NSNotFound; i = [indexSet indexGreaterThanIndex: i]) {... } ' – Richard

+0

Eso también funciona. :) En realidad, eso es más limpio que mi muestra. ¡Robando! –

+0

Como consejo, si indexSet es nulo, el bucle se repetirá infinitamente porque lee: 'para (! NSUInteger i = 0; i = NSNotFound; i = 0) {}' –

3

decir que quiero representar un conjunto disperso de los índices con un NSIndexSet (que por supuesto es para lo que sirve).

[el énfasis es mío]

En realidad, no, no lo es.El documentation dice esto:

No use índice de conjuntos para almacenar una colección arbitraria de valores enteros porque almacenan índices conjuntos de índices como rangos ordenados.

Así que si lo está usando para almacenar una matriz dispersa de enteros, es bastante ineficiente. Además, la única forma de obtener el n-ésimo índice es iterar desde un extremo. Sería mejor usar una matriz.

+0

Pshaw, semántica! Si solo necesitaba un conjunto conocido de índices contiguos, usaría un NSRange. :) Para los otros métodos de la clase, hay un valor para mí, pero también quiero este comportamiento de obtener por posición, aunque creo que no está allí. –

0

una decisión más:

- (NSUInteger)indexAtIndex:(NSUInteger)index { 
    __block NSUInteger result = NSNotFound; 
    __block NSUInteger aCounter = 0; 

    [self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) { 
     if (aCounter == index) { 
     result = idx; 
     *stop = YES; 

     } else { 
     aCounter++; 
     } 
    }]; 

    return result; 
} 
Cuestiones relacionadas