【问题标题】:canonical way to randomize an NSArray in Objective-C在 Objective-C 中随机化 NSArray 的规范方法
【发布时间】:2010-10-21 22:21:31
【问题描述】:

在 Objective-C 中是否有规范的方法来随机化一个数组?

【问题讨论】:

标签: iphone objective-c random


【解决方案1】:

如果这是您所要求的,SDK 中没有内置任何内容。

但是,您几乎可以使用任何您想要的随机化或洗牌算法。不同的算法在随机性、效率等方面有不同的权衡。

http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms

对于从可变数组开始“就地”随机播放的算法,请使用

insertObject:atIndex:
removeObjectAtIndex:

对于重建数组的算法,将原始数组提供给它并构建一个新数组。

【讨论】:

    【解决方案2】:
    if ([array count] > 1) {
        for (NSUInteger shuffleIndex = [array count] - 1; shuffleIndex > 0; shuffleIndex--)
            [array exchangeObjectAtIndex:shuffleIndex withObjectAtIndex:random() % (shuffleIndex + 1)];
    }
    

    确保使用 srandomdev() 或 srandom() 为 random() 函数播种。

    【讨论】:

    • 你写的作为实例方法没有意义。由于代码存在,它应该只是一个函数或类方法。习惯上,它应该是一个 NSArray 实例方法,它返回一个新的、打乱的数组或一个 NSMutableArray 实例方法,它自己打乱。
    • 没错,我只是在这里演示代码,并不真正担心将其归类。我也忘了提到用 srandomdev() 或 srandom() 来播种 random() 函数。
    • 此代码因取模而略有偏差;有关更多信息,请参阅en.wikipedia.org/wiki/Fisher-Yates_shuffle#Modulo_bias
    【解决方案3】:

    我的实用程序库在 NSMutableArray 上定义了这个类别来做到这一点:

    @interface NSMutableArray (ArchUtils_Shuffle)
    - (void)shuffle;
    @end
    
    // Chooses a random integer below n without bias.
    // Computes m, a power of two slightly above n, and takes random() modulo m,
    // then throws away the random number if it's between n and m.
    // (More naive techniques, like taking random() modulo n, introduce a bias 
    // towards smaller numbers in the range.)
    static NSUInteger random_below(NSUInteger n) {
        NSUInteger m = 1;
    
        // Compute smallest power of two greater than n.
        // There's probably a faster solution than this loop, but bit-twiddling
        // isn't my specialty.
        do {
            m <<= 1;
        } while(m < n);
    
        NSUInteger ret;
    
        do {
            ret = random() % m;
        } while(ret >= n);
    
        return ret;
    }
    
    @implementation NSMutableArray (ArchUtils_Shuffle)
    
    - (void)shuffle {
        // http://en.wikipedia.org/wiki/Knuth_shuffle
    
        for(NSUInteger i = [self count]; i > 1; i--) {
            NSUInteger j = random_below(i);
            [self exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
        }
    }
    
    @end
    

    确保在调用之前的某个时间为随机数生成器(例如srandom(time(NULL)))播种;否则输出不会很随机。

    【讨论】:

    • 爱它!感谢分享。我现在对你的实用程序库的其余部分非常好奇。
    • @bresc 随机使用srandom(time(NULL)) 或使用arc4random() 代替
    • 只是我添加的一件小事:if (n == 0) { return 0; }。你不能通过 0,但如果你这样做了,你就会陷入第二个循环。
    • 如果您使用的是 OSX 10.7 或 iOS 4.3 或更高版本,您可以使用 arc4random_uniform(upper_bound) 而不必编写或使用 random_below(i) 函数。
    • @LavaSlider 好点!这是实现stackoverflow.com/a/10258341/396133
    【解决方案4】:

    没有在NSArray(即有一个像arrayWithRandomizedIndices这样的实例方法)或NSMutableArray(即有一个像randomizeIndices这样的方法)上创建一个类别的规范方法。

    这是我的图书馆中的一个示例,属于NSMutableArray 上的一个类别。它将随机重新排序数组,而不是随机排列一些条目。

    - (void) randomizeIndices
    {
      if (self == nil || [self count] <= 1)
      {
        return;
      }
    
      int count = [self count];
    
      NSMutableArray* copySelf = [NSMutableArray arrayWithArray:self];
      NSMutableArray* mutableResultArray = [NSMutableArray alloc];
      mutableResultArray = [mutableResultArray initWithCapacity:count];
      [mutableResultArray autorelease];
    
      int objectsMovedCount = 0;
    
      for (int i = 0; i < count; i++)
      {
        int index = rand() % (count - objectsMovedCount);
        id anObject = [copySelf objectAtIndex:index];
        [mutableResultArray addObject:anObject];
        [copySelf removeObjectAtIndex:index];
        objectsMovedCount++;
      }
      [self setArray:mutableResultArray];
    }
    

    在调用此方法之前或在该方法的早期调用srand(time(0)); 或类似的。

    【讨论】:

      【解决方案5】:

      我的解决方案是一个类别方法,它返回数组的副本(自动释放),其中元素随机化(使用 arc4random)。

      @interface NSArray (CMRandomised)
      
      /* Returns a copy of the array with elements re-ordered randomly */
      - (NSArray *)randomised;
      
      @end
      
      /* Returns a random integer number between low and high inclusive */
      static inline int randomInt(int low, int high)
      {
          return (arc4random() % (high-low+1)) + low;
      }
      
      @implementation NSArray (CMRandomised)
      
      - (NSArray *)randomised
      {
          NSMutableArray *randomised = [NSMutableArray arrayWithCapacity:[self count]];
      
          for (id object in self) {
              NSUInteger index = randomInt(0, [randomised count]);
              [randomised insertObject:object atIndex:index];
          }
          return randomised;
      }
      
      @end
      

      【讨论】:

        【解决方案6】:

        来了!

        - (NSArray*)shuffleArray:(NSArray*)array {
        
            NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:array];
        
            for(NSUInteger i = [array count]; i > 1; i--) {
                NSUInteger j = arc4random_uniform(i);
                [temp exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
            }
        
            return [NSArray arrayWithArray:temp];
        }
        

        【讨论】:

          【解决方案7】:

          NSArray 随机化作为 Objective-C 类别的方法:

          @implementation NSArray (NGDataDynamics)
          
          - (NSArray *)jumbled
          {
            NSMutableArray *jumbled = self.mutableCopy;
          
            NSUInteger idx = self.count-1;
            while(idx)
            {
              [jumbled exchangeObjectAtIndex:idx
                           withObjectAtIndex:arc4random_uniform(idx)];
              idx--;
            }
          
            return jumbled;
          }
          
          @end
          

          如所见:NSArray Randomization & Psychedelia

          【讨论】:

            猜你喜欢
            • 2012-06-05
            • 1970-01-01
            • 2012-08-09
            • 2017-04-20
            • 2012-03-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多