Вырезать NSArray из конца массива - PullRequest
7 голосов
/ 14 июня 2011

Каков наилучший способ "нарезать" NSArray от конца, а не от начала массива (например, найти подмассив, содержащий последние несколько элементов NSArray неизвестной длины)? В Python вы можете использовать отрицательные индексы для этого, например ::

new_list = old_list[-5:-3]

Какой самый естественный способ сделать это в Objective-C?

1 Ответ

17 голосов
/ 14 июня 2011

Нет ничего, что соответствовало бы хорошему синтаксису Python для этого, но вы могли бы сделать:

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

Вы также можете написать категорию для NSArray, например:

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

Если вы хотите пойти по этому пути, исходный код Python непременно окупит учебу. объект списка создает объект среза , когда выполняется операция среза. Соответствующий метод для объекта среза - PySlice_GetIndicesEx. Вам просто нужно быть осторожным, превращая эти индексы в NSRange. Поскольку комментарий в этой функции предупреждает: «это сложнее понять, чем вы думаете». (Я постараюсь разобраться с этим позже.)

ОБНОВЛЕНИЕ: Здесь у нас есть категория среза на NSArray. Логика расчета индекса в значительной степени прямолинейна из кода Python, на который я ссылался выше. * На самом деле это намного проще, чем я думал сначала, если вам не нужно беспокоиться о плавной части фрагмента Python. Я прошел через несколько тестов, и похоже, что он работает так же, как и версия 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

* Поэтому я думаю, что мне нужно включить ссылку на Лицензию Python , а также отметить, что это может все еще быть «Copyright © 2001-2010 Python Software Foundation; Все права защищены », потому что, хотя это выглядит для меня как отдельная производная работа, защищенная авторским правом, я не юрист.

...