如何在cocoa / objective C中获得数组数组的所有水平组合

时间:2014-04-01 16:40:56

标签: objective-c arrays cocoa

我有一个给定的矩阵(数组数组),如下所示:

NSArray *line1 = @[@"a1",@"b1",@"c1"];
NSArray *line2 = @[@"a2",@"b2",@"c2"];
NSArray *line3 = @[@"a3",@"b3",@"c3"];
NSArray *line4 = @[@"a4",@"b4",@"c4"];

NSArray *matrix = @[fret1,fret2,fret3];

定义的是,每一行的计数是相同的,但我不知道,每行有多少行和多少个条目。

我希望从每一行获得所有可能的值变化。

所以我有这个代码,它有效:

    NSArray *line1 = @[@"a1",@"b1",@"c1"];
    NSArray *line2 = @[@"a2",@"b2",@"c2"];
    NSArray *line3 = @[@"a3",@"b3",@"c3"];
    NSArray *line4 = @[@"a4",@"b4",@"c4"];

    NSArray *matrix = @[line1,line2,line3,line4];

    NSMutableArray *result = [NSMutableArray arrayWithCapacity:50];

    NSInteger colCount = matrix.count;
    NSInteger rowCount = [(NSArray*)[matrix objectAtIndex:0] count];

    for (int lc1 = 0; lc1 < colCount; lc1++) {
        for (int lc2 = 0; lc2 < colCount; lc2++) {
            for (int lc3 = 0; lc3 < colCount; lc3++) {
                        NSString *row1 = [(NSArray*)[matrix objectAtIndex:lc1] objectAtIndex:0];
                        NSString *row2 = [(NSArray*)[matrix objectAtIndex:lc2] objectAtIndex:1];
                        NSString *row3 = [(NSArray*)[matrix objectAtIndex:lc3] objectAtIndex:2];

                        [result addObject:[NSString stringWithFormat:@"%@ %@ %@„,row1,row2,row3]];
            }
        }
    }

    for (int i = 0; i < result.count; i++) {
        NSLog(@"%2ld: %@",(long)i,(NSString*)[result objectAtIndex:i]);
    }

上面的代码给出了以下结果:

 0: a1 b1 c1
 1: a1 b1 c2
 2: a1 b1 c3
 3: a1 b1 c4
 4: a1 b2 c1
 5: a1 b2 c2
 6: a1 b2 c3
 7: a1 b2 c4
 8: a1 b3 c1
 9: a1 b3 c2
10: a1 b3 c3
11: a1 b3 c4
12: a1 b4 c1
13: a1 b4 c2
14: a1 b4 c3
15: a1 b4 c4
16: a2 b1 c1
17: a2 b1 c2
18: a2 b1 c3
19: a2 b1 c4
20: a2 b2 c1
21: a2 b2 c2
22: a2 b2 c3
23: a2 b2 c4
24: a2 b3 c1
25: a2 b3 c2
26: a2 b3 c3
27: a2 b3 c4
28: a2 b4 c1
29: a2 b4 c2
30: a2 b4 c3
31: a2 b4 c4
32: a3 b1 c1
33: a3 b1 c2
34: a3 b1 c3
35: a3 b1 c4
36: a3 b2 c1
37: a3 b2 c2
38: a3 b2 c3
39: a3 b2 c4
40: a3 b3 c1
41: a3 b3 c2
42: a3 b3 c3
43: a3 b3 c4
44: a3 b4 c1
45: a3 b4 c2
46: a3 b4 c3
47: a3 b4 c4
48: a4 b1 c1
49: a4 b1 c2
50: a4 b1 c3
51: a4 b1 c4
52: a4 b2 c1
53: a4 b2 c2
54: a4 b2 c3
55: a4 b2 c4
56: a4 b3 c1
57: a4 b3 c2
58: a4 b3 c3
59: a4 b3 c4
60: a4 b4 c1
61: a4 b4 c2
62: a4 b4 c3
63: a4 b4 c4

但是我怎么能动态地这样做,因为我不知道编译时我有多少行和列?

2 个答案:

答案 0 :(得分:1)

首先定义一个函数,将矩阵的一列的所有元素追加到所有元素 以前获得的组合:

NSArray *combinations(NSArray *a, NSArray *matrix, NSUInteger column)
{
    NSMutableArray *result = [NSMutableArray array];
    for (NSString *elem in a) {
        for (NSArray *row in matrix) {
            NSString *tmp = [elem stringByAppendingFormat:@" %@", row[column]];
            [result addObject:tmp];
        }
    }
    return result;
}

然后以下给出想要的结果(适用于任意数字 行和列):

NSArray *line1 = @[@"a1",@"b1",@"c1"];
NSArray *line2 = @[@"a2",@"b2",@"c2"];
NSArray *line3 = @[@"a3",@"b3",@"c3"];
NSArray *line4 = @[@"a4",@"b4",@"c4"];
NSArray *matrix = @[line1,line2,line3,line4];

NSArray *result = @[@""];
for (NSUInteger column = 0; column < [line1 count]; column++) {
    result = combinations(result, matrix, column);
}

for (NSUInteger i = 0; i < [result count]; i++) {
    NSLog(@"%2lu: %@",(unsigned long)i,(NSString*)[result objectAtIndex:i]);
}

要了解其工作原理,让我们看看循环的每个步骤会发生什么。 在第一步中,列#0的所有元素都附加到空字符串:

 0:  a1
 1:  a2
 2:  a3
 3:  a4

在第二步中,列#1的所有元素都附加到来自的所有字符串 第一步:

 0:  a1 b1
 1:  a1 b2
 2:  a1 b3
 3:  a1 b4
 4:  a2 b1
 5:  a2 b2
 6:  a2 b3
 7:  a2 b4
 8:  a3 b1
 9:  a3 b2
10:  a3 b3
11:  a3 b4
12:  a4 b1
13:  a4 b2
14:  a4 b3
15:  a4 b4

在第三步中,第2列的所有元素都附加到所有字符串中 第二步:

 0:  a1 b1 c1
 1:  a1 b1 c2
 2:  a1 b1 c3
 3:  a1 b1 c4
 4:  a1 b2 c1
 5:  a1 b2 c2
 6:  a1 b2 c3
...
58:  a4 b3 c3
59:  a4 b3 c4
60:  a4 b4 c1
61:  a4 b4 c2
62:  a4 b4 c3
63:  a4 b4 c4

在你的例子中有所有(有三列),但它的工作原理相同 列或行。

答案 1 :(得分:1)

@MartinR已经展示了一个很好的迭代解决方案,这里是一个递归的解决方案,为那些认为递归/只是为了好玩的人使用块: - ):

NSArray *line1 = @[@"a1",@"b1",@"c1"];
NSArray *line2 = @[@"a2",@"b2",@"c2"];
NSArray *line3 = @[@"a3",@"b3",@"c3"];
NSArray *line4 = @[@"a4",@"b4",@"c4"];

NSArray *matrix = @[line1,line2,line3,line4];

NSUInteger colCount = matrix.count;
NSUInteger rowCount = [matrix[0] count];

NSMutableArray *result = [NSMutableArray new];

NSMutableArray *sample = [NSMutableArray new];

__block __unsafe_unretained void (^weakCombinations)(NSUInteger);
void (^combinations)(NSUInteger);
weakCombinations = combinations = ^(NSUInteger row)
{
    if (row == rowCount)
    {
        // have a complete sample
        [result addObject:[sample componentsJoinedByString:@" "]];
    }
    else
    {
        // iterate over current column and recurse
        for (NSUInteger ix = 0; ix < colCount; ix++)
        {
            sample[row] = matrix[ix][row];
            weakCombinations(row+1);
        }
    }
};

combinations(0);

for (int i = 0; i < result.count; i++)
{
    NSLog(@"%2ld: %@",(long)i,(NSString*)[result objectAtIndex:i]);
}

算法很简单,构建了通过矩阵的样本路径,当行到达路径时,用空格连接并添加到解集中。

注意:递归块过去不那么混乱,但在ARC下保留__block变量,因此我们需要与weakCombinations进行跳舞。 __unsafe_unretained的使用在这里是安全的,并且比使用__weak稍微有效一点,并且因为我们使用的块调用性能比方法更接近函数,为什么不多刮一点?