我怎样才能最容易地在Cocoa中展平三维数组?

时间:2013-06-14 13:44:05

标签: objective-c cocoa

说我有一个这样的数组:

NSArray *threeDimensionalArray = @[
 @[     
     @[ @"Peter", @"Paul", @"Mary" ], @[ @"Joe", @"Jane" ]
  ],
 @[
     @[ @"Alice", @"Bob" ]
  ]
];

我希望它成为:

@[ @"Peter", @"Paul", @"Mary", @"Joe", @"Jane", @"Alice", @"Bob" ]

我怎样才能最轻松地创建这个扁平化阵列?

3 个答案:

答案 0 :(得分:27)

键值编码(KVC)集合运算符@unionOfArrays展平了一个级别的数组,因此应用它两次会产生所需的结果。

集合运算符(@count除外)需要一个到集合属性的键路径,并且由于我们的对象本身已经是数组(因此也是集合),因此关键路径必须是self

因此,我们需要使用@unionOfArrays关键路径应用self两次,从而产生以下KVC调用以展平3D数组:

NSArray *flattenedArray = [threeDimensionalArray valueForKeyPath: @"@unionOfArrays.self.@unionOfArrays.self"];

答案 1 :(得分:2)

我意识到这个线程有点旧,但我需要一个解决方案,其中深度级别并不重要。可以将以下方法添加到NSArray上的类别中。我还包括了这些方法的测试:

// This is the method that would be used from an outside class
- (NSArray *)flatten {
    NSArray *array = self;
    while (![array isFlattened]) {
        array = [array flattenOneLevel];
    }
    return [NSArray arrayWithArray:array];
}

- (NSArray *)flattenOneLevel {
    NSMutableArray *array = [NSMutableArray array];
    for (id object in self) {
        [object isKindOfClass:self.class] ? [array addObjectsFromArray:object] : [array addObject:object];
    }
    return array;
}

- (BOOL)isFlattened {
    BOOL flattened = YES;
    for (id object in self) {
        if ([object isKindOfClass:self.class]) {
            flattened = NO;
            break;
        }
    }
    return flattened;
}

以下是对这些方法的测试,以确保其正常工作:

it(@"should flatten an array", ^{
    NSArray *initialArray = @[@[@23, @354, @1, @[@7], @[@[@3]]], @[@[@890], @2, @[@[@6], @8]]];
    NSArray *expectedArray = @[@23, @354, @1, @7, @3, @890, @2, @6, @8];
    expect([initialArray flatten]).equal(expectedArray);
});

答案 2 :(得分:1)

使用递归的替代答案,它将占用更多内存(在堆栈上),但对于那些喜欢递归的人来说,更容易阅读:

- (NSArray *) flatten;
{
    NSMutableArray *flattedArray = [NSMutableArray new];

    for (id item in self) {
        if ([[item class] isSubclassOfClass:[NSArray class]]) {
            [flattedArray addObjectsFromArray:[item flatten]];
        } else {
            [flattedArray addObject:item];
        }
    }

    return flattedArray;
}

扩展测试:

+ (void) unitTests;
{
    NSArray *flattenedArray;

    NSArray *initialArray1 = @[@[@23, @354, @1, @[@7], @[@[@3]]], @[@[@890], @2, @[@[@6], @8]]];
    NSArray *expectedArray1 = @[@23, @354, @1, @7, @3, @890, @2, @6, @8];
    flattenedArray = [initialArray1 flatten];
    SPASLogDetail(@"flattenedArray: %@", flattenedArray);
    AssertIf(![flattenedArray isEqualToArray:expectedArray1], @"Arrays are not equal");

    NSArray *initialArray2 = @[@[@23, @354, @1, [@[@7] mutableCopy], @[@[@3]]], @[[@[@890] mutableCopy], @2, @[@[@6], @8]]];
    NSArray *expectedArray2 = expectedArray1;
    flattenedArray = [initialArray2 flatten];
    SPASLogDetail(@"flattenedArray: %@", flattenedArray);
    AssertIf(![flattenedArray isEqualToArray:expectedArray2], @"Arrays are not equal");
}