从数组末尾切片 NSArray

发布于 2024-11-15 01:18:35 字数 200 浏览 4 评论 0原文

从数组末尾而不是开头“切片” NSArray 的最佳方法是什么(例如,查找包含 NSArray 最后几个元素的子数组)代码> 长度未知)?在 Python 中,您可以使用负索引来完成此操作,例如:

new_list = old_list[-5:-3]

在 Objective-C 中执行此操作最自然的方法是什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

才能让你更想念 2024-11-22 01:18:35

没有什么可以与 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 许可证 的链接,并请注意, 可能仍然是“版权所有 © 2001-2010 Python Software Foundation;保留所有权利”,因为虽然这在我看来像是一个单独受版权保护的衍生作品,但我不是律师。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文