【问题标题】:Reading random values from an array从数组中读取随机值
【发布时间】:2011-08-12 22:43:12
【问题描述】:

我有一个包含 14 个字符串的数组。我想向用户显示这 14 个字符串中的每一个而不重复。我得到的最接近的是创建一个整数数组并将它们的值改组,然后使用 int 数组中的一个数字作为索引从字符串数组中读取:

    //appDelegate.randomRiddles is an array of integers that has integer values randomly
     appDelegate.randomRiddlesCounter++;
     NSNumber *index=[appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
     int i = [index intValue];
     while(i>[appDelegate.currentRiddlesContent count]){
        appDelegate.randomRiddlesCounter++;
        index=[appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
        i = [index intValue];
                    }
hintText.text = [[appDelegate.currentRiddlesContent objectAtIndex:i] objectForKey:@"hint"];
questionText.text = [[appDelegate.currentRiddlesContent objectAtIndex:i] objectForKey:@"question"];

但我的方式导致崩溃和重复。哦,每次我从字符串数组中读取一个值时,该字符串都会从数组中删除,使其计数减少 1。所以这有点复杂。

【问题讨论】:

    标签: objective-c random


    【解决方案1】:

    像这样获取数组中的元素:

    int position = arc4random() % ([myArray count]);
    

    这样,即使 count 减一,也没关系,因为在没有更多可能的值之前,您仍然可以获得有效的下一个位置值。

    【讨论】:

    • @Mohabitar,如果每次你得到一个,对象就会从数组中删除。
    • 不应该是 arc4random() % [myArray count] 给出从 0 到 count-1 的数字吗?否则,最后一个元素将保持为最后一个元素,如果 count = 1,您将执行arc4random() % 0,这是不行的。如果您想从数组中删除项目,您可以这样说或发布执行此操作的代码。
    【解决方案2】:

    “没有重复”我假设您的意思是您想在再次使用相同的字符串之前使用数组中的每个字符串一次,而不是要过滤数组以使其不包含重复的字符串。

    这是一个使用 Fisher-Yates shuffle 的函数:

    /** @brief Takes an array and produces a shuffled array.
     *
     *  The new array will contain retained references to 
     *  the objects in the original array
     *
     *  @param original The array containing the objects to shuffle.
     *  @return A new, autoreleased array with all of the objects of 
     *          the original array but in a random order.
     */
    NSArray *shuffledArrayFromArray(NSArray *original) {
        NSMutableArray *shuffled = [NSMutableArray array];
        NSUInteger count = [original count];
        if (count > 0) {
            [shuffled addObject:[original objectAtIndex:0]];
    
            NSUInteger j;
            for (NSUInteger i = 1; i < count; ++i) {
                j = arc4random() % i; // simple but may have a modulo bias
                [shuffled addObject:[shuffled objectAtIndex:j]];
                [shuffled replaceObjectAtIndex:j 
                                    withObject:[original objectAtIndex:i]];
            }
        }
    
        return shuffled; // still autoreleased
    }
    

    如果您想保持谜语、提示和问题之间的关系,那么我建议使用NSDictionary 来存储每组相关字符串,而不是将它们存储在单独的数组中。

    【讨论】:

    • 不知道它被称为“Fisher-Yates shuffle”。我一直将其称为“随机排列”。这是一个很好的半随机算法,可以轻松确保您只浏览每个项目一次。
    【解决方案3】:

    使用NSMutableArray 可以轻松完成这项任务。为此,只需从数组中删除一个随机元素,将其显示给用户。

    将可变数组声明为实例变量

    NSMutableArray * questions;
    

    应用启动时,使用 myArray 中的值填充

    questions = [[NSMutableArray alloc] initWithArray:myArray]];
    

    然后,要从数组中获取一个随机元素并将其删除,请执行以下操作:

    int randomIndex = (arc4random() % [questions count]);
    NSDictionary * anObj = [[[questions objectAtIndex:randomIndex] retain] autorelease];
    [questions removeObjectAtIndex:randomIndex];
    // do something with element
    hintText.text = [anObj objectForKey:@"hint"];
    questionText.text = [anObj objectForKey:@"question"];
    

    【讨论】:

      【解决方案4】:

      不需要输入那么多。要打乱数组,只需使用随机比较器对其进行排序:

      #include <stdlib.h>
      
      NSInteger shuffleCmp(id a, id b, void* c)
      {
          return (arc4random() & 1) ? NSOrderedAscending : NSOrderedDescending;
      }
      
      NSArray* shuffled = [original sortedArrayUsingFunction:shuffleCmp context:0];
      

      【讨论】:

      【解决方案5】:

      您可以将数组复制到 NSMutableArray 中并随机播放。如何打乱数组的简单演示:

      #import <Foundation/Foundation.h>
      
      int main (int argc, const char * argv[])
      {
      
          NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      
          // Original array, here initialised with 1..9
          NSArray *arr = [NSArray arrayWithObjects: 
                          [NSNumber numberWithInt: 1],
                          [NSNumber numberWithInt: 2],
                          [NSNumber numberWithInt: 3],
                          [NSNumber numberWithInt: 4],
                          [NSNumber numberWithInt: 5],
                          [NSNumber numberWithInt: 6],
                          [NSNumber numberWithInt: 7],
                          [NSNumber numberWithInt: 8],
                          [NSNumber numberWithInt: 9],
                          nil];
      
          // Array that will be shuffled
          NSMutableArray *shuffled = [NSMutableArray arrayWithArray: arr];
      
          // Shuffle array
          for (NSUInteger i = shuffled.count - 1; i > 0; i--) 
          {
              NSUInteger index = rand() % i;
              NSNumber *temp = [shuffled objectAtIndex: index];
              [shuffled removeObjectAtIndex: index];
              NSNumber *top = [shuffled lastObject];
              [shuffled removeLastObject];
              [shuffled insertObject: top atIndex: index];
              [shuffled addObject: temp];
          }
      
          // Display shuffled array
          for (NSNumber *num in shuffled)
          {
              NSLog(@"%@", num);
          }
      
          [pool drain];
          return 0;
      }
      

      请注意,这里的所有数组和数字都是自动释放的,但在您的代码中,您可能需要处理内存管理。

      如果您不必将元素保留在数组中,您可以简化它(也请参阅 Oscar Gomez 的回答):

              NSUInteger index = rand() % shuffled.count;
              NSLog(@"%@", [shuffled objectAtIndex: index]);
              [shuffled removeObjectAtIndex: index];
      

      最后,shuffled 将为空。您也必须更改循环条件:

          for (NSUInteger i = 0; i < shuffled.count; i++)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-19
        • 1970-01-01
        • 2022-10-08
        • 2010-12-11
        • 1970-01-01
        相关资源
        最近更新 更多