从数组末尾切片NSArray

jrd*_*oko 7 reverse objective-c slice nsarray ios

NSArray从数组的末尾而不是从头开始"切片"的最佳方法是什么(例如,找到包含NSArray未知长度的最后几个元素的子数组)?在Python中,您可以使用负数索引来实现此目的,例如:

new_list = old_list[-5:-3]
Run Code Online (Sandbox Code Playgroud)

Objective-C中最自然的方法是什么?

Jos*_*ell 17

没有什么可以匹配Python的漂亮语法,但你可以这样做:

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

你也可以写一个类别NSArray,例如:

@interface NSArray (jrdioko_slice)
- (NSArray *) jrdioko_sliceFrom:(NSInteger)start to:(NSInteger)stop;
@end
Run Code Online (Sandbox Code Playgroud)

如果你想走这条路,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
Run Code Online (Sandbox Code Playgroud)

*因此,我认为我需要包含一个Python许可证的链接,并注意到这可能仍然是"版权所有©2001-2010 Python软件基金会; 保留所有权利",因为虽然这看起来像是一个单独的版权衍生作品,但我不是律师.

  • +1提及类别,也适用于jrdioko_sliceFrom :) (3认同)
  • @jrdioko:哦,那太尴尬了.试图避免一个一个错误并走进它.你是正确的指出来的; 应该只是数n. (2认同)