2011-06-13 21 views
7

¿Cuál es la mejor manera de "cortar" un NSArray desde el final, en lugar del comienzo, del conjunto (por ejemplo, encontrar el subcampo que contiene los últimos elementos de un NSArray de longitud desconocida)? En Python, puede utilizar los índices negativos de lograr esto, por ejemplo .:Slice NSArray desde el final del conjunto

new_list = old_list[-5:-3] 

¿Cuál es la forma más natural de hacer esto en Objective-C?

Respuesta

17

No hay nada que coincida con buena sintaxis de Python para esto, pero que podría ser:

NSUInteger count = [myArray count]; 
NSArray * slice = [myArray subarrayWithRange:(NSRange){count-n, n}]; 

También podría escribir una categoría para NSArray, algo así como:

@interface NSArray (jrdioko_slice) 
- (NSArray *) jrdioko_sliceFrom:(NSInteger)start to:(NSInteger)stop; 
@end 

Si desea vaya por esta ruta, la fuente de Python ciertamente pagará el estudio. Un list object crea un slice object cuando se realiza una operación de división. El método relevante en un objeto de división es PySlice_GetIndicesEx. Tendrás que tener cuidado de convertir esos índices en NSRange. Como el comentario en esa función advierte "esto es más difícil de hacer lo correcto de lo que piensas". (Trataré de analizar esto más tarde.)

ACTUALIZACIÓN: Aquí tenemos una categoría de división en NSArray. La lógica de cálculo del índice es bastante parecida al código de Python al que me he vinculado anteriormente. * En realidad, es mucho más fácil de lo que pensé al principio si no tienes que preocuparte por la parte de zancada de una porción de Python. Lo he pasado con algunas pruebas y parece funcionar igual que la versión de Python.

@interface NSArray (WSS_Slice) 
- (NSArray *)WSS_arrayBySlicingFrom:(NSInteger)start to:(NSInteger)stop; 
@end 

// Python allows skipping any of the indexes of a slice and supplies default 
// values. Skipping an argument to a method is not possible, so (ab)use 
// NSNotFound as "not specified" index value. The other way to do this would 
// be with varargs, which might be even handier if one decided to implement 
// the stride functionality. 
enum { 
    WSS_SliceNoIndex = NSNotFound 
}; 

@implementation NSArray (WSS_Slice) 

- (NSArray *)WSS_arrayBySlicingFrom:(NSInteger)start to:(NSInteger)stop { 
    // There's an important caveat here: specifying the parameters as 
    // NSInteger allows negative indexes, but limits the method's 
    // (theoretical) use: the maximum size of an NSArray is NSUIntegerMax, 
    // which is quite a bit larger than NSIntegerMax. 
    NSUInteger count = [self count]; 

    // Due to this caveat, bail if the array is too big. 
    if(count >= NSIntegerMax) return nil; 

    // Define default start and stop 
    NSInteger defaultStart = 0; 
    NSInteger defaultStop = count; 

    // Set start to default if not specified 
    if(start == WSS_SliceNoIndex){ 
     start = defaultStart; 
    } 
    else { 
     // If start is negative, change it to the correct positive index. 
     if(start < 0) start += count; 
     // Correct for out-of-bounds index: 
     // If it's _still_ negative, set it to 0 
     if(start < 0) start = 0; 
     // If it's past the end, set it to just include the last item 
     if(start > count) start = count; 
    } 

    // Perform all the same calculations on stop 
    if(stop == WSS_SliceNoIndex){ 
     stop = defaultStop; 
    } 
    else { 
     if(stop < 0) stop += count; 
     if(stop < 0) stop = 0; 
     if(stop > count) stop = count; 
    } 

    // Calculate slice length with corrected indexes 
    NSInteger sliceLength = stop - start; 

    // If no slice, return a new empty array 
    if(sliceLength <= 0){ 
     return [NSArray array]; 
    } 
    else { 
     return [self subarrayWithRange:(NSRange){start, sliceLength}]; 
    } 

} 
@end 

* Por tanto, yo creo que tenga que incluir un enlace a la Python License y tener en cuenta que esto puede siendo “Copyright © 2001-2010 Python Software Foundation; Todos los derechos reservados ", porque aunque esto me parece un trabajo derivado por derechos de autor por separado, no soy un abogado.

+3

+1 para mencionar categorías, también para jrdioko_sliceFrom :) – Tatvamasi

+0

En su respuesta inicial, ¿por qué es 'count-n-1' en lugar de' count-n'? – jrdioko

+2

@jrdioko: Oh, eso es embarazoso. Intentando evitar el error de "uno por uno" y caminando directamente hacia él. Estás en lo correcto al señalar eso; debería ser solo count-n. –

Cuestiones relacionadas