所有可能的组合,无需重复NSArray

时间:2014-06-28 13:57:10

标签: objective-c math nsarray combinatorics

假设我有一个包含3个数字的数组:

NSArray *array = @[@1, @2, @3];

我想做所有组合而不重复 所以我需要的是这个:
(1)
(2)
(3)
(1,2)
(2,3)
(1,3)
(1,2,3)

我目前的代码是:

NSArray *array = @[@1, @2, @3];
int numberOfCardsOTable = [array count];

//NSLog(@"array = %@", array);

for (int lenghtOfArray = 1; lenghtOfArray <= numberOfCardsOTable; lenghtOfArray++)
{
    for (int i = 0; i < numberOfCardsOTable; i++)
    {
        // array bound check
        if (i + lenghtOfArray > numberOfCardsOTable) {
            continue;
        }

        NSArray *subArray = [[NSMutableArray alloc] init];

        subArray = [array subarrayWithRange:NSMakeRange(i, lenghtOfArray)];

        NSLog(@"array = %@", subArray);
    }
}

但缺少此代码(1,3)。

我需要为最多8个数字的源数组执行此操作 有8个数字,有255种组合,我的算法会遗漏很多,因此会有很多if s。

2 个答案:

答案 0 :(得分:6)

由于您似乎希望组合与原始组合的顺序相同,所以您所做的与计数到2 num_choices 并选择与设置位对应的对象相同。你可以通过我为NSIndexSet编写的类别方法提供一些帮助,使这个变得非常简单。

@implementation NSIndexSet (WSSNoncontiguous)

+ (instancetype)WSSIndexSetFromMask:(uint64_t)mask
{
    NSMutableIndexSet * set = [NSMutableIndexSet indexSet];

    for( uint64_t i = 0; i < 64; i++ ){
        if( mask & (1ull << i) ){
            [set addIndex:i];
        }
    }

    return set;
}

@end

这将创建一个NSIndexSet,其内容是掩码中设置的位的索引。然后,您可以使用-[NSArray objectsAtIndexes:]的索引集来获取组合:

NSArray * choices = @[...];
uint64_t num_combos = 1ull << [choices count];    // 2**count
NSMutableArray * combos = [NSMutableArray new];
for( uint64_t i = 1; i < num_combos; i++ ){
    NSIndexSet * indexes = [NSIndexSet WSSIndexSetFromMask:i];
    [combos addObject:[choices objectsAtIndexes:indexes]];
}

显然,这仅适用于成员数量为64或更少的choices,但无论如何最终会成为非常大量的组合。

答案 1 :(得分:1)

范围永远不会适用于这种情况。

有趣的是,您可能需要考虑以下事项。

NSArray *array = @[@1, @2, @3];
//NSArray *array = @[@1, @2, @3, @4];
int numberOfCardsOTable = [array count];

//this can be calculated too - a row in Pascal's triangle
NSArray *pascalsRow = @[@1, @3, @3, @1];
//NSArray *pascalsRow = @[@1, @4, @6, @4, @1];

int pIndex = 1;
int endIdx = [[pascalsRow objectAtIndex:pIndex] integerValue];
int outputLength;

//process the number of expected terms in pascal row
for (int i = 0; i < [pascalsRow count]; i++)
{
    //skipping first term
    outputLength = i;
    if(outputLength > 0)
    {
        for (int j = i; j <= endIdx; j++)
        {
            if(outputLength > 1)
            {
                for(int k = 1; k <= endIdx; k++)
                {
                    NSLog(@"j = %i, k = %i, ... outputLength = %i", j, k, outputLength);
                }
                j = endIdx;
            }
            else
                NSLog(@"j = %i, ... outputLength = %i", j, outputLength);
        }

        if(pIndex < numberOfCardsOTable)
        {
            pIndex++;
            NSLog(@"pIndex = %i, endIdx = %i", pIndex, endIdx);
            endIdx = [[pascalsRow objectAtIndex:pIndex] integerValue];
        }

        if(endIdx == 1 && outputLength == numberOfCardsOTable)
            NSLog(@"... outputLength = %i", outputLength);
    }
}

我留下p = 4注释掉,以防你想快速查看该用例。这种方法至少可以为您提供正确数量的术语和长度。我会留给你构建所需的输出。

输出:

[32771:70b] j = 1, ... outputLength = 1
[32771:70b] j = 2, ... outputLength = 1
[32771:70b] j = 3, ... outputLength = 1
[32771:70b] pIndex = 2, endIdx = 3
[32771:70b] j = 2, k = 1, ... outputLength = 2
[32771:70b] j = 2, k = 2, ... outputLength = 2
[32771:70b] j = 2, k = 3, ... outputLength = 2
[32771:70b] pIndex = 3, endIdx = 3
[32771:70b] ... outputLength = 3