Skip to content

Instantly share code, notes, and snippets.

@yiplee
Last active December 14, 2016 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yiplee/a20f0b9ca6e09dcdfe26b129afb7bec8 to your computer and use it in GitHub Desktop.
Save yiplee/a20f0b9ca6e09dcdfe26b129afb7bec8 to your computer and use it in GitHub Desktop.
给你一个嵌套的 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
@tangqiaoboy
Copy link

cool, 我的解法和你一样~

@tangqiaoboy
Copy link

有个问题是,[array copy] 其实是浅拷贝,所以如果原数组的嵌套数组有变化,还是会影响迭代逻辑工作。

@yiplee
Copy link
Author

yiplee commented Dec 14, 2016

@tangqiaoboy 如果要整个 copy 一遍的话效率太低了,迭代过程中嵌套数组有变化无法避免。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment