iOS: как сгенерировать 8 уникальных случайных целых чисел?

Мне нужно сгенерировать 8 случайных целых чисел, но они должны быть уникальными, то есть не повторяться.

Например, мне нужно 8 чисел в диапазоне от 1 до 8.

Я видел arc4random, но не знаю, как сделать их уникальными?

Решение

-(NSMutableArray *)getRandomInts:(int)amount from:(int)fromInt to:(int)toInt {

  if ((toInt - fromInt) +1 < amount) {
      return nil;    
  }

  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < amount) {

      r = (arc4random() % toInt) + fromInt;
      if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
          [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
      }
  }
  return uniqueNumbers;
}

person Jules    schedule 27.05.2011    source источник
comment
есть только 1 выбор из 8 уникальных целых чисел из диапазона 1..8... Кажется, что-то в вопросе нуждается в исправлении;)   -  person Vladimir    schedule 27.05.2011
comment
@Vladimir: Кажется, подразумевается, что в этом случае порядок является случайным.   -  person Mike DeSimone    schedule 27.05.2011
comment
Аааа должно быть toInt - fromInt :) все готово.   -  person Jules    schedule 27.05.2011
comment
ваш код решения при выполнении от 1 до 10 дает правильный ответ, но при выполнении от 51 до 60 дает 54, 72, 53, 102, 60, 87, 52, 84, 75, 109   -  person raw3d    schedule 09.11.2012


Ответы (6)


-(NSMutableArray *)getEightRandom {
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random();
    if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
      [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
    }
  }
  return uniqueNumbers;
}

Если вы хотите ограничить числа меньше некоторого порога M, вы можете сделать это следующим образом:

-(NSMutableArray *)getEightRandomLessThan:(int)M {
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random() % M; // ADD 1 TO GET NUMBERS BETWEEN 1 AND M RATHER THAN 0 and M-1
    if (![uniqueNumbers containsObject:[NSNumber numberWithInt:r]]) {
      [uniqueNumbers addObject:[NSNumber numberWithInt:r]];
    }
  }
  return uniqueNumbers;
}

Если M=8 или даже если M близко к 8 (например, 9 или 10), то это займет некоторое время, и вы можете быть более умным.

-(NSMutableArray *)getEightRandomLessThan:(int)M {
  NSMutableArray *listOfNumbers = [[NSMutableArray alloc] init];
  for (int i=0 ; i<M ; ++i) {
    [listOfNumbers addObject:[NSNumber numberWithInt:i]]; // ADD 1 TO GET NUMBERS BETWEEN 1 AND M RATHER THAN 0 and M-1
  }
  NSMutableArray *uniqueNumbers = [[[NSMutableArray alloc] init] autorelease];
  int r;
  while ([uniqueNumbers count] < 8) {
    r = arc4random() % [listOfNumbers count];
    if (![uniqueNumbers containsObject:[listOfNumbers objectAtIndex:r]]) {
      [uniqueNumbers addObject:[listOfNumbers objectAtIndex:r]];
    }
  }
  [listOfNumbers release];
  return uniqueNumbers;
}
person PengOne    schedule 27.05.2011
comment
#include <stdlib.h> Кроме того, в PengOne есть опечатка: это arc4random, а не acr4random. - person Art Gillespie; 27.05.2011
comment
-1. Этот ответ, хотя он может работать без видимых недостатков для небольших чисел, учит плохому решению этой проблемы, которая на самом деле является проблемой перетасовки. Завершение этого алгоритма никогда не гарантируется. См. ответ @Art Gillespie для соответствующего фрагмента кода. (Я голосую здесь как указатель для потенциальных будущих читателей, так как этот ответ был принят.) - person Ben Zotto; 27.05.2011
comment
@quixoto: с вероятностью 1 он завершится за конечное время. Кроме того, третье предложение дает алгоритм генерации перестановок, который завершается за 8 шагов. Более того, он не обязательно хочет 8 последовательных чисел. - person PengOne; 28.05.2011
comment
@quixoto: ваш комментарий является лучшим и более информативным указателем для потенциальных будущих читателей, чем отрицательный голос за правильный ответ, просто к вашему сведению - person PengOne; 28.05.2011
comment
-1 В настоящее время ваш третий список ведет себя почти так же, как ваш второй список, потому что вы не удаляете выбранные номера из [listOfNumbers] после того, как они были использованы. Кроме того, вам не нужен if (![uniqueNumbers containsObject: проверьте больше, если вы используете метод listOfNumbers. - person occulus; 12.06.2012
comment
Вау, за целый год этого никто не заметил? - person occulus; 12.06.2012
comment
Именование методов не соответствует соглашениям Obj-C. Подобные методы не должны начинаться с get. - person Sulthan; 28.04.2013

Уникальность — это то, что вам нужно обеспечить — API-интерфейсы случайности не сделают этого за вас.

Как было предложено, вы можете сгенерировать число, а затем проверить, не сталкивается ли оно с чем-то, что вы уже сгенерировали, и если да, попробуйте еще раз. Обратите внимание, однако, что в зависимости от количества чисел и размера диапазона это становится алгоритмом, который не имеет гарантированной конечной точки.

Если вы действительно просто пытаетесь получить непрерывный набор чисел в случайном порядке, это не лучший способ сделать это, так как это может занять непредсказуемо много времени. В этом случае лучше сначала создать массив всех желаемых значений, а затем «перетасовать» массив. Лучше всего перетасовать Fisher-Yates, но если вы этого не сделаете, нужно, чтобы это было совершенно беспристрастно, вы также можете сделать то, что описано здесь.

person Ben Zotto    schedule 27.05.2011
comment
У меня есть 50 вопросов, должны будут прийти случайно. как я могу дать? - person Vineesh TP; 20.07.2012

Проверка уже сгенерированных чисел потенциально затратна (теоретически это может занять вечность). Однако это решаемая проблема. Вам нужен алгоритм перетасовки, например Fisher-Yates_shuffle.

На iOS, вероятно, что-то вроде:

NSMutableArray *randSequence = [[NSMutableArray alloc] initWithCapacity:8];
for (int ii = 1; ii < 9; ++ii)
    [randSequence addObject:[NSNumber numberWithInt:ii]];

for (int ii = 8; ii > 0; --ii) {
    int r = arc4random() % (ii + 1);
    [randSequence exchangeObjectAtIndex:ii withObjectAtIndex:r];

// you can now iterate over the numbers in `randSequence` to get
// your sequence in random order
person Art Gillespie    schedule 27.05.2011
comment
если ii идет от 8 и увеличивается, то он всегда будет › 0, следовательно, это определенно никогда не прекратится. - person PengOne; 27.05.2011
comment
Это довольно поздно, но разве вы не должны принимать во внимание предвзятость? Не следует ли вам изменить int r = arc4random() % 8 на int r = arc4random() % i ? - person Byte; 03.09.2012
comment
@Byte, вы абсолютно правы, еще лучше, чтобы это было int r = arc4random_uniform(i)+1; - person Kaan Dedeoglu; 28.04.2013

Сохраните числа в массиве, и каждый раз, когда вы генерируете следующий, проверяйте, не существует ли он уже в массиве. Если нет, то добавьте его и продолжайте.

person Luke    schedule 27.05.2011

Вот какой-то псевдокод

  1. Для каждого числа 1-8 генерируется случайное число.
  2. Добавьте случайное число и целое число в словарь в виде пары ключ-значение
  3. получить все ключи словаря в виде массива (подсказка: взгляните на метод allKeys)
  4. Отсортируйте этот массив (по возрастанию или по убыванию не важно)
  5. Теперь для каждого из этих чисел в качестве ключа получите соответствующее целое число из словаря
person Abizern    schedule 27.05.2011
comment
Это работает, но перетасовка лучше из-за эффективности, хотя это не должно иметь большого значения только с восемью целыми числами. - person vakio; 27.05.2011
comment
Я просто хотел предоставить другой способ переупорядочения списка без написания кода. Насчет эффективности - не могу сказать без профилирования и анализа других алгоритмов. - person Abizern; 27.05.2011

Попробуйте этот код... это даст вам все возможные уникальные числа, установленные в массиве Mutable...

-(NSInteger) randomNumber {
NSInteger newRandomNumber = (NSInteger) arc4random() % 10;
NSInteger uniqueNumber;
if ([self.arrayContainingNumbers containsObject: [NSNumber numberWithInteger:newRandomNumber]]) {
    [self randomNumber];
    } else {
    [self.arrayContainingNumbers addObject: [NSNumber numberWithInteger:newRandomNumber]];
}
uniqueNumber = [[self.mutableArrayContainingNumbers lastObject]integerValue];
     NSLog(@"new Unique Number is %ld",(long)uniqueNumber);

return uniqueNumber;  
}

Не забудьте добавить этот метод :)

    -(NSMutableArray *) arrayContainingNumbers {
if (!_mutableArrayContainingNumbers) {
    _mutableArrayContainingNumbers = [[NSMutableArray alloc] init];
}
return _mutableArrayContainingNumbers; 
}
person Chetan    schedule 05.08.2015