2010-12-28 11 views
14

Mi sembra una domanda stupida perché mi sembra che il mio caso d'uso debba essere abbastanza comune.NSIndexSet "-indexAtIndex:"?

Dire che voglio rappresentare un insieme sparse di indici con un NSIndexSet (che è ovviamente a cosa serve). Posso usare -firstIndex per ottenere quello più basso e -lastIndex per il più alto, ma qual è il modo canonico per ottenere un singolo indice arbitrario nel mezzo, dato il suo "indice"? I documenti non mi hanno lasciato chiaro.

E.g. se ho un indice impostato con gli indici {0, 5, 8, 10, 12, 28}, e voglio dire "dammi il quarto indice" e mi aspetto di tornare indietro di 10 (o 12 suppongo che dipende se conto lo zeroth, ma non entriamo in quello, capisci cosa intendo).

Nota che non sto eseguendo "enumerazione" nell'intero set di indici. Ad un certo punto nel tempo voglio solo sapere qual è l'ennesimo indice nell'insieme per ordine numerico.

Forse la mia struttura dati è errata ("set" di solito non sono progettati per tale accesso ordinato), ma sembra non esserci NSIndexArray di cui parlare.

Mi manca qualcosa di ovvio?

Grazie!

+2

Perché non usare NSArray? –

+0

Forse è possibile aggirare questa risposta: http://stackoverflow.com/questions/905828/get-nsindexset-from-nsarray – chuckSaldana

+1

@Neilvert: potrei finire per farlo, ma inscatolare gli interi in NSNumbers sembrava eccessivo quando la struttura dei dati per contenere gli indici sembrava così conveniente! :) I set –

risposta

4

Credo che lo NSIndexSet memorizzi gli indici utilizzando gli intervalli, quindi non è necessariamente un modo rapido per restituire l'indice nth. Puoi enumerare un contatore finché il contatore non raggiunge il tuo indice target:

NSUInteger index = [indexSet firstIndex]; 

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

Questo dovrebbe darti il ​​4 ° indice. Si potrebbe anche aggiungere il metodo come metodo di categoria se si desidera:

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

Ma, come hai detto, questo non può essere la migliore struttura di dati da usare in modo da considerare che più prima di andare con qualcosa di simile.

+0

Sì, sembra che non mi manchi qualcosa di ovvio. Sfortunatamente, se memorizza internamente gli indici come intervalli, potrebbe esporre indexAtIndex in modo più efficiente di quello che posso fare in una categoria, ma punto preso. Grazie. –

6

NSIndexSet non è progettato per questo tipo di accesso. Di solito, si enumera attraverso gli indici in un set in questo modo:

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

@pluto sottolinea questo ciclo for è più semplice:

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

Ci sono alcuni metodi basati su blocchi che sono nuove per NSIndexSet come di Mac OS X 10.6/iOS 4.0, ma non li ho ancora revisionati.

Dovrebbe essere banale modificare l'esempio precedente per mantenere un conteggio in esecuzione degli indici e fermarsi quando raggiunge il quarto indice nel set. ;)

+0

che praticamente dice tutto, anche se avrei scritto il codice di esempio come ciclo for: 'for (NSUInteger i = [indexSet firstIndex]; i! = NSNotFound; i = [indexSet indexGreaterThanIndex: i]) {... } – Richard

+0

Anche questo funziona. :) In realtà, è più pulito del mio campione. Rubare! –

+0

Come un suggerimento, se indexSet è pari a zero, il ciclo for ciclo volontà infinitamente perché legge: 'per (! NSUInteger i = 0; i = NSNotFound; i = 0) {}' –

3

dire che voglio rappresentare un insieme sparso di indici con una NSIndexSet (che naturalmente è quello che è per).

[corsivo mio]

In realtà, no non lo è.Il documentation dice questo:

Si consiglia di non utilizzare indice imposta per memorizzare una raccolta arbitraria di valori interi a causa indici set indice dei negozi come intervalli ordinati.

Quindi, se lo si utilizza per memorizzare una matrice sparsa di interi, è del tutto inefficiente. Inoltre, l'unico modo per ottenere l'ennesimo indice è iterare da un'estremità. Faresti meglio a usare un array. più

+0

Pshaw, semantica! Se avessi bisogno solo di un insieme di indici noti-contigui, userei un NSRange. :) C'è un valore per me negli altri metodi della classe, ma desidero anche questo comportamento di get-by-position, anche se mi rendo conto che non è lì. –

0

Una decisione:

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