Slice NSArray from end of array

社会主义新天地 提交于 2020-01-12 18:56:37

问题


What is the best way to "slice" an NSArray from the end, rather than the beginning, of the array (for example, finding the subarray containing the last few elements of a NSArray of unknown length)? In Python, you can use negative indices to accomplish this, e.g.:

new_list = old_list[-5:-3]

What's the most natural way to do this in Objective-C?


回答1:


There's nothing to match Python's nice syntax for this, but you could do:

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

You could also write up a category for NSArray, something like:

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

If you want to go this route, the Python source will certainly repay study. A list object creates a slice object when a slice operation is performed. The relevant method on a slice object is PySlice_GetIndicesEx. You'll just have to be careful turning those indexes into an NSRange. As the comment in that function warns "this is harder to get right than you might think". (I'll try to take a crack at this later.)

UPDATE: Here we have a slice category on NSArray. The index calculation logic is pretty much straight out of the Python code that I linked to above.* It's actually a lot easier than I thought at first if you don't have to worry about the stride part of a Python slice. I've run this through a few tests and it seems to work the same as the Python version.

@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

*Therefore I think I need to include a link to the Python License and also note that this may still be “Copyright © 2001-2010 Python Software Foundation; All Rights Reserved”, because although this looks to me like a separately-copyrightable derivative work, I ain't a lawyer.



来源:https://stackoverflow.com/questions/6337339/slice-nsarray-from-end-of-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!