1

例子。我有一个包含 15 个对象的数组。我想从给定的索引开始枚举。说从索引 5 开始,然后是上面的索引,下面的索引,上面的,下面的等等……我确实希望它环绕。

所以我的例子中的索引顺序是。5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13

拥有类似于以下行的方法签名会很棒,但我不需要它来批准答案:

- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block

如何才能做到这一点?想避免复制数组等。

在这篇文章中,我们没有环绕枚举 NSArray 从给定索引开始双向搜索(没有环绕)

4

2 回答 2

2

借用@omz,这里是包装变体,它更简单:

@implementation NSArray (Extensions)

- (void)enumerateFromIndex:(NSUInteger)index wrapAroundAndGoBothWays:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
    BOOL stop = NO;
    NSUInteger actual = index;
    for (NSUInteger i = 0; i < self.count && !stop; i++) {
        actual += (2*(i%2)-1)*i;
        actual = (self.count + actual)%self.count;
        block([self objectAtIndex:actual], actual, &stop);
    }
}

@end
于 2013-01-16T13:44:13.107 回答
1

这是一个数学问题。有一个很好的解决方案。但是,它涉及预先对索引列表进行排序。

这个想法是将0到15的整数放在一个圆圈上,并按照它们在轴上出现的顺序排列元素。

由于在 ObjC 中执行此操作非常繁琐,因此我提出了 python 解决方案:

from math import pi, cos

def circlesort(N, start):
    eps = 1e-8
    res = range(N)
    def f(x):
        return -cos(2*pi*(x-start-eps)/N)
    res.sort( lambda x,y:cmp(f(x), f(y)) )
    return res

然后

print circlesort(15, 5)

输出

[5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13]

这是期望的结果。

编辑

好的,这是一个 C 实现:

#include <stdlib.h>
#include <math.h>
#define sign(x) ((x)>0?1:(x)<0?-1:0)

void circlesort(int* values, int N, int start){
    double f(int x)
    {
        return -cos(2*M_PI*((double)(x-start)-.25)/N);
    }
    int compare (const void * a, const void * b)
    {
        return sign( f(*(int*)a) - f(*(int*)b) );
    }
    qsort (values, N, sizeof(int), compare);
}

这将对长度为 N 的整数数组进行循环排序。像这样使用它:

int i, N = 15;
int indexes[N];
for (i=0;i<N;i++) 
    indexes[i] = i;
circlesort(indexes, N, 5);

现在数组indexes按所需顺序排序。因为有嵌套函数,你应该添加-fnested-functions到编译器标志。

编辑 2

考虑到有一个更简单的解决方案(参见我的另一个答案)这一事实,这个解决方案相当学术。

于 2013-01-16T10:34:30.740 回答