1

Xcodeでarc4randomを使用してランダム値を生成する際に問題が発生しました。すでに取得されている番号を乱数から除外したいと思います。これは私が書いたアルゴリズムです

int randomValue =  (arc4random() % numberofquest)+ 1;
int kk=1;

if (kk==1) {

//first time add the first random value
[oldquest addObject: randomValue];
    }
else {
        //control if the number is already in the vector
        for (int j=1; j<[oldquest count]; j++)
        {

            if (randomValue==oldquest[j])
            {

                randomValue =  (arc4random() % numerodomande)+ 1;
            }
            else
            {
                [oldquest addObject: randomValue];
            }
        }

}
kk=kk+1

しかし、それは機能しません。おそらく、配列内のrandomvalueとj番目のオブジェクトが比較できないためだと思います(最初のオブジェクトと2番目の文字列?)。誰か助けてくれませんか?

4

3 に答える 3

2

申し訳ありませんが、アレスの答えはほぼ正しかったです。2つの異なるNSNumberオブジェクトを比較できます。

これが私の解決策です:

- (int) generateRandomNumber {
    int number = arc4random() % 100;

    if ([chosen_numbers indexOfObject:[NSNumber numberWithInt:number]]!=NSNotFound)
        number = [self generateRandomNumber];

    [chosen_numbers addObject:[NSNumber numberWithInt:number]];
    return number;
}

Alessandroは実装に問題があるため、UIViewControllerクラス内の例を次に示します。これは100個の数字で機能します。

#import "ViewController.h"

@implementation ViewController {
    NSMutableArray * chosen_numbers;    
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    chosen_numbers = [[NSMutableArray alloc] init];

    for(int i = 0; i<90; i++) {
        NSLog(@"number: %d",[self generateRandomNumber]);
    }
}

- (int) generateRandomNumber {
    int number = arc4random() % 100;

    if ([chosen_numbers indexOfObject:[NSNumber numberWithInt:number]]!=NSNotFound)
        number = [self generateRandomNumber];

    [chosen_numbers addObject:[NSNumber numberWithInt:number]];
    return number;
}

@end
于 2013-02-22T18:58:35.283 に答える
1

これはどう:

    -(void) generateRandomNumber {

        int randomValue =  arc4random_uniform(numberofquest) + 1;

        if([oldQuest indexOfObject:[NSNumber numberWithInt:randomValue] == NSNotFound) {
            //Unique value
            [oldQuest addObject:[NSNumber numberWithInt:randomValue]];
        }
        else {
            //Value already exists. Look for another one
            return [self generateRandomNumber];

        }
    }

明らかに、oldQuestは以前に初期化されたNSMutableArrayインスタンスです。

于 2013-02-22T18:49:55.490 に答える
1

あなたは正しいです-それはここにあるので機能しません:

            if (randomValue==oldquest[j])

をオブジェクトと比較しようとしintています...NSArrayはオブジェクトのみを格納できます。実際、この行はその理由で機能しないはずです。

[oldquest addObject: randomValue];

intをNSNumberとしてボックス化し、それを配列に格納する必要があります。

NSNumber* boxedRandomValue = [NSNumber numberWithInt:randomValue];
[oldquest addObject: boxedRandomValue];

-(int)intValue次に、値を比較する前に、NSNumberインスタンスメソッドを使用してボックスを解除します。

 if (randomValue==[oldquest[j] intValue])

アップデート

あなたが注意しなければならない他のいくつかの問題があります:

  • kkの値は、テストの反復ごとに1にリセットされるため、kk == 1常にtrueであり、else句が呼び出されることはありません。このコードブロックの外側で一度だけ設定する必要があります(たとえば、プロパティにし、初期化時に1に設定してから、ここでアクセスしてインクリメントすることができます)。さらに良いことに、代わりに[oldquest count]を使用してください:if ([oldquest count]==0) {} else {}。その後、あなたはあなたのkkカウンターを完全に省くことができます。

  • forループはj=1で始まります。配列の最初の項目(項目0)をアドレス指定するには、これをj=0にする必要があります。

アップデート2

この行:randomValue = (arc4random() % numerodomande)+ 1チェックループ内の位置が原因​​で、他のあらゆる種類の問題が発生します。次のいずれかの提案を試してください。

  • returnデュープに出くわしたとき。配列に番号が追加されません...

  • ループ内でBOOLテストを設定し、外部で処理します。

    BOOL repeatedValue = NO;
    for (int j=0; j<[self.oldquest count]; j++){
        if (randomValue==[self.oldquest[j] intValue]) {
            repeatedValue = YES;
            break;
        }
    }
    if (repeatedValue){
        NSLog (@"value repeated");
        [self addRandom];  
        //recursive call to this code block, 
        //assuming it is a method called `addRandom`
    }
    
  • 最後の提案のコンパクトバージョンを試してください(Odrakirのソリューションと同様)-addRandom再帰的に呼び出す方法を確認できるように、メソッドで囲みました。

      - (void) addRandom {
        int numberofquest = 5;
        int randomValue =  (arc4random() % numberofquest)+ 1;
        NSNumber* boxedValue = [NSNumber numberWithInt:randomValue];
        if ([self.oldquest indexOfObject:boxedValue]==NSNotFound) {
            [self.oldquest addObject: boxedValue];
        } else {
            [self addRandom];
        }
    }
    

    (一意の番号が見つかるまでループを実行すると、番号の合計セットがに制限されるためnumberofquest、注意する必要があります。したがって、完全なセットがある場合は、無限ループになる可能性があります。)

  • NSMutableArrayを使用する代わりに、代わりにMutableOrderedSetを使用できます。これは一意のオブジェクトの順序付けられたコレクションであるため、オブジェクトを2回追加することはありません。

@interfaceで

@property (nonatomic, strong) NSMutableOrderedSet setOfRandoms;

@implementationで

int randomValue =  (arc4random() % numberofquest)+ 1;
NSNumber randomValueBoxed = [NSNumber numberWithInt:randomValue];
[setOfRandoms addObject:randomValueBoxed];

アップデート3

以前のヒントは、それが興味のあるランダムのリストであると想定していました。これは、自己完結型のメソッドで新しい一意のランダムintを返すための完全なソリューションです。

@interfaceに2つのプロパティを設定し、どこかで初期化する必要があります。

@property (nonatomic, assign) int maxRand;
    //stores the highest allowed random number

@property (nonatomic, strong) NSMutableArray* oldRands;
    //stores the previously generated numbers

uniqueRandom毎回1からself.maxRandまでの一意の乱数を返します。許容されるすべての数値が返された場合は、0が返されます。

- (int) uniqueRandom {
    int result = 0;
    if ([self.oldRands count] != self.maxRand) {
        int randomValue =  (arc4random() %  self.maxRand )+ 1;
        NSNumber* boxedValue = [NSNumber numberWithInt:randomValue];
        if ([self.oldRands indexOfObject:boxedValue]==NSNotFound) {
            [self.oldRands addObject: boxedValue];
            result = randomValue;
        } else {
             result = [self uniqueRandom];
        }
    }
    return result;
}

self.oldRandsもリセットしない限り、初期化されたself.maxRandを変更しても意味がないことを考慮する必要があります。したがって、またはの代わりにconstまたはを使用したり、イニシャライザーに関連付けたりすることができます。#defineself.oldRands

于 2013-02-22T19:04:21.163 に答える