How to generate non repeating random number

2019-02-15 15:09发布

问题:

I am trying to randomize numbers in an array. I am able to do that using arc4random() % [indexes count]

My problem is - If an array consists of 20 items, every time the array shuffles, in a batch of 5, different number should appear. Example :

first shuffle: 1,4,2,5,6.

second shuffle: 7,12,9,15,3

-(IBAction)randomNumbers:(UIButton *)sender
{
    int length = 10; // int length = [yourArray count];

    NSMutableArray *indexes = [[NSMutableArray alloc] initWithCapacity:length];
    for (int i=0; i<5; i++)
        [indexes addObject:[NSNumber numberWithInt:i]];

    NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:length];

    while ([indexes count])
    {
        int index = arc4random() % [indexes count];
        [shuffle addObject:[indexes objectAtIndex:index]];
        [indexes removeObjectAtIndex:index];
    }

    //    for (int i=0; i<[shuffle count]; i++)
    NSLog(@"%@", [shuffle description]);
}

回答1:

As per your requirement....kindly check this code

Make this a property

@synthesize alreadyGeneratedNumbers;

Add these methods in your .m

-(int)generateRandomNumber{

    int TOTAL_NUMBER=20;

    int low_bound = 0;
    int high_bound = TOTAL_NUMBER;
    int width = high_bound - low_bound;
    int randomNumber = low_bound + arc4random() % width;

    return randomNumber;
}


-(IBAction)randomNumbers:(UIButton *)sender
{

    NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:5];

    BOOL contains=YES;
    while ([shuffle count]<5) {
        NSNumber *generatedNumber=[NSNumber numberWithInt:[self generateRandomNumber]];
        //NSLog(@"->%@",generatedNumber);

        if (![alreadyGeneratedNumbers containsObject:generatedNumber]) {
            [shuffle addObject:generatedNumber];
            contains=NO;
            [alreadyGeneratedNumbers addObject:generatedNumber];
        }
    }

    NSLog(@"shuffle %@",shuffle);
    NSLog(@"Next Batch");


    if ([alreadyGeneratedNumbers count] >= TOTAL_NUMBER) {
        NSLog(@"\nGame over, Want to play once again?");//or similar kind of thing.
        [alreadyGeneratedNumbers removeAllObjects];
    }


}

Still I feel you need to some changes like

it will give you correct value, but what if user pressed 5th time?

out of 20 numbers you already picked 4 sets of 5 number, on on 6th time it will be in loop to search for next set of numbers and will become infinite.

So what you can do is, keep the track of shuffle and once it reaches the limit i.e, 20/5=4 disable the random button.



回答2:

Declare array that contains already generated number in extension or header file

@property (strong, nonatomic)NSMutableArray *existingNums;
@property (assign, nonatomic)NSInteger maxLimit;
@property (assign, nonatomic)NSInteger minLimit;

Then implement given code in implementation file

@synthesize existingNums;
@synthesize maxLimit;
@synthesize minLimit;

- (NSInteger)randomNumber {

    if(!existingNums)
        existingNums = [NSMutableArray array];

    while (YES) {

        NSNumber *randonNum = [NSNumber numberWithInteger:minLimit+arc4random()%maxLimit];

        if([existingNums containsObject:randonNum]) {

            if([existingNums count] == (maxLimit - minLimit))
                return -1; // All possible numbers generated in the given range

            continue;
        }

        [existingNums addObject:randonNum];

        return [randonNum integerValue];
    }

    return -1;   // return error
}

Hope this will help you :)



回答3:

This one works for me:

    NSMutableArray *numbers = [NSMutableArray new];
    BOOL addElement = YES;
    int limit = 100; // Range from 0 to 36
    int numElem = 10; // Number of elements
    do
    {
        int ranNum = (arc4random() % limit) +1;
        if ([numbers count] < numElem) {
            for (NSNumber *oneNumber in numbers) {
                addElement =([oneNumber intValue] != ranNum) ? YES:NO;
                if (!addElement) break;
            }
            if (addElement) [numbers addObject:[NSNumber numberWithInt:ranNum]];
        } else {
            break;
        }
    } while (1);
    NSLog(@"%@",numbers);


回答4:

The problem with all these answers is that you need to review your previous generated random numbers and that takes extra time if you need a large number of random integers.

Another solution is using cryptography:

  1. Generate a random key
  2. Iterate between 0..n
  3. Encrypt each integer and apply modulo the number of alternatives do you want to use to the output of the function.

There are some extra details to take into account that don't matter for your case.