Enumerate NSArray starting at givven index searching both ways (wrap around)

房东的猫 提交于 2019-12-11 10:32:47

问题


Example. I've got an array with 15 objects. I want to start enumerating from a given index. Say start at index 5 and then the index above, the index under, above, under etc... I do want it to wrap around.

So the order of indexes in my example would be. 5, 6, 4, 7, 3, 8, 2, 9, 1, 10, 0, 11, 14, 12, 13

It would be great to have a method signature similar to following line, but I don't require that to approva an answer:

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

How can this be done? Would like to avoid copying array etc.

At this post we do it with no wrap around: Enumerate NSArray starting at givven index searching both ways (no wrap around)


回答1:


Borrowing from @omz, here is the wrapping variant, which is even simpler:

@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



回答2:


This is a mathematical problem. There is a nice solution. However, it involves sorting the list of indexes in advance.

The idea is to lay the integers from 0 to 15 out on a circle and taking the elements in the order they appear on an axis.

Since doing this in ObjC is so tedious, I present the python solution:

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

then

print circlesort(15, 5)

outputs

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

which is the desired result.

EDIT

Okay, here is a C implementation:

#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);
}

This will circlesort an array of integers of lenght N. Use it like this:

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

Now the array indexes is sorted in the desired order. Because there are nested functions, you should add -fnested-functions to the compiler flags.

EDIT 2

Considering the fact that there is a much simpler solution (see my other answer) this one is rather academic.



来源:https://stackoverflow.com/questions/14354514/enumerate-nsarray-starting-at-givven-index-searching-both-ways-wrap-around

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