给你一个嵌套的 NSArray 数据,实现一个迭代器类,该类提供一个 next() 方法,可以依次的取出这个 NSArray 中的数据。 比如 NSArray 如果是 [1,[4,3],6,[5,[1,0]]], 则最终应该输出:1, 4, 3, 6, 5, 1, 0 。 另外,实现一个 allObjects 方法,可以一次性取出所有元素。
// | |
// NSArray+FlatEnumerator.h | |
// Flay Array | |
// | |
// Created by yiplee on 2016/12/13. | |
// | |
#import <Foundation/Foundation.h> | |
@class NSArrayFlatEnumerator; | |
@interface NSArray (FlatEnumerator) | |
- (NSEnumerator *) flatEnumerator; | |
- (NSEnumerator *) reverseFlatEnumerator; | |
- (NSArray *) allObjects; | |
- (id) next; | |
@end |
// | |
// NSArray+FlatEnumerator.m | |
// Flay Array | |
// | |
// Created by yiplee on 2016/12/13. | |
// | |
#import "NSArray+FlatEnumerator.h" | |
#import "NSArrayFlatEnumerator.h" | |
#import <objc/objc-runtime.h> | |
@implementation NSArray (FlatEnumerator) | |
- (NSEnumerator *) flatEnumerator | |
{ | |
return [NSArrayFlatEnumerator flatEnumeratorWithArray:self]; | |
} | |
- (NSEnumerator *) reverseFlatEnumerator | |
{ | |
return [NSArrayFlatEnumerator reverseFlatEnumeratorWithArray:self]; | |
} | |
- (NSArray *) allObjects | |
{ | |
return [[self flatEnumerator] allObjects]; | |
} | |
- (NSEnumerator *) _private_enumerator | |
{ | |
SEL key = _cmd; | |
NSArrayFlatEnumerator *enumator = objc_getAssociatedObject(self, key); | |
if (!enumator) { | |
enumator = (NSArrayFlatEnumerator*)[self flatEnumerator]; | |
objc_setAssociatedObject(self, key, enumator, OBJC_ASSOCIATION_RETAIN); | |
} | |
return enumator; | |
} | |
- (id) next | |
{ | |
return [[self _private_enumerator] nextObject]; | |
} | |
@end |
// | |
// NSArrayFlatEnumerator.h | |
// Flay Array | |
// | |
// Created by yiplee on 2016/12/13. | |
// | |
#import <Foundation/Foundation.h> | |
@interface NSArrayFlatEnumerator : NSEnumerator | |
+ (instancetype) flatEnumeratorWithArray:(NSArray *)array; | |
+ (instancetype) reverseFlatEnumeratorWithArray:(NSArray *)array; | |
@end |
// | |
// NSArrayFlatEnumerator.m | |
// Flay Array | |
// | |
// Created by yiplee on 2016/12/13. | |
// | |
#import "NSArrayFlatEnumerator.h" | |
#import <stack> | |
struct FlatArrayPoint { | |
__unsafe_unretained NSArray *currentArray; | |
NSInteger currentIndex; | |
}; | |
typedef struct FlatArrayPoint FlatArrayPoint; | |
#define FlatArrayInitialIndex NSIntegerMin | |
static FlatArrayPoint* flatArrayPointWithArray(NSArray *array) { | |
FlatArrayPoint *point = (FlatArrayPoint*)calloc(1, sizeof(FlatArrayPoint)); | |
point->currentArray = array; | |
point->currentIndex = FlatArrayInitialIndex; | |
return point; | |
} | |
static void freeFlatArrayPoint(FlatArrayPoint *point) { | |
point->currentArray = nil; | |
free(point); | |
} | |
@implementation NSArrayFlatEnumerator | |
{ | |
NSArray *_array; | |
std::stack<FlatArrayPoint *> _stack; | |
BOOL _reverse; | |
} | |
- (void) dealloc | |
{ | |
while (!_stack.empty()) { | |
FlatArrayPoint *point = _stack.top(); | |
_stack.pop(); | |
freeFlatArrayPoint(point); | |
} | |
} | |
- (instancetype) initWithArray:(NSArray *)array reverse:(BOOL)reverse; | |
{ | |
NSParameterAssert(array); | |
self = [self init]; | |
if (self) { | |
_array = [NSArray arrayWithArray:array]; | |
_reverse = reverse; | |
FlatArrayPoint *point = flatArrayPointWithArray(_array); | |
_stack.push(point); | |
} | |
return self; | |
} | |
+ (instancetype) flatEnumeratorWithArray:(NSArray *)array | |
{ | |
return [[self alloc] initWithArray:array reverse:NO]; | |
} | |
+ (instancetype) reverseFlatEnumeratorWithArray:(NSArray *)array | |
{ | |
return [[self alloc] initWithArray:array reverse:YES]; | |
} | |
- (id) nextObject | |
{ | |
if (_stack.empty()) return nil; | |
FlatArrayPoint *topPoint = _stack.top(); | |
BOOL isArrayLooped = NO; | |
if (!topPoint->currentArray || topPoint->currentArray.count == 0) { | |
isArrayLooped = YES; | |
goto loop; | |
} | |
if (FlatArrayInitialIndex == topPoint->currentIndex) { | |
topPoint->currentIndex = _reverse ? (topPoint->currentArray.count - 1) : 0; | |
} else { | |
topPoint->currentIndex += _reverse ? -1 : 1; | |
} | |
if (topPoint->currentIndex < 0 || topPoint->currentIndex >= topPoint->currentArray.count) { | |
isArrayLooped = YES; | |
goto loop; | |
} | |
loop: | |
if (isArrayLooped) { | |
_stack.pop(); | |
freeFlatArrayPoint(topPoint); | |
return [self nextObject]; | |
} | |
id item = topPoint->currentArray[topPoint->currentIndex]; | |
if ([item isKindOfClass:[NSArray class]]) { | |
FlatArrayPoint *point = flatArrayPointWithArray(item); | |
_stack.push(point); | |
return [self nextObject]; | |
} else { | |
return item; | |
} | |
} | |
@end |
This comment has been minimized.
This comment has been minimized.
有个问题是,[array copy] 其实是浅拷贝,所以如果原数组的嵌套数组有变化,还是会影响迭代逻辑工作。 |
This comment has been minimized.
This comment has been minimized.
@tangqiaoboy 如果要整个 copy 一遍的话效率太低了,迭代过程中嵌套数组有变化无法避免。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
cool, 我的解法和你一样~