All possible combinations without repetition from an NSArray

梦想的初衷 提交于 2019-12-10 19:29:40

问题


Let say that I have an array with 3 numbers:

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

And I want to make all combinations without repetition.
So what I need is this:
( 1 )
( 2 )
( 3 )
( 1, 2 )
( 2, 3 )
( 1, 3 )
( 1, 2, 3 )

The current code that I have is this:

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);
    }
}

But this code is missing ( 1, 3 ).

I will need to do this for a source array up to 8 numbers long.
With 8 numbers there are 255 combinations, and my algorithm will miss a lot, so that will be lots of ifs.


回答1:


Since you seem to want your combinations to be in the same order as the original set, what you're doing is the same as counting to 2num_choices and selecting the objects corresponding to the set bits. You can make this really easy with a little help from a category method I've written for 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

This creates an NSIndexSet whose contents are the indexes of the bits that are set in the mask. You can then use that index set with -[NSArray objectsAtIndexes:] to grab your combinations:

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]];
}

Obviously this only works for a choices that has sixty-four or fewer members, but that would end up being a very large number of combos anyways.




回答2:


Range will never work for this scenario.

Interestingly, you may want to consider the following.

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);
    }
}

I left p=4 commented out in case you wanted to quickly see that use case. This approach will at least provide you with the correct number of terms and their lengths. I will leave it to you to construct the desired output.

Output:

[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


来源:https://stackoverflow.com/questions/24467519/all-possible-combinations-without-repetition-from-an-nsarray

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!