从数组中读取随机值

6

我有一个14个字符串的数组。我想显示这14个字符串中的每一个,但不要重复。我尝试过创建一个整数数组并随机打乱它们的值,然后使用整数数组中的一个数字作为索引从字符串数组中读取:

    //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。这使得问题稍微有点复杂。

5个回答

7

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

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

即使计数器减少了一个,也没有关系,因为在没有更多可能值的情况下,您仍将获得有效的下一个位置值。

1
@Mohabitar,如果每次获取一个对象时,该对象都从数组中删除,则不行。 - Oscar Gomez
难道不应该是 arc4random() % [myArray count] 吗?这样可以得到从 0 到 count-1 的数字。否则,最后一个元素将保持不变,如果 count = 1,则会执行 arc4random() % 0,这是不正确的。如果您想从数组中删除项目,可以说明或发布相应代码。 - Rudy Velthuis

4
我假定“去重”指的是在使用相同字符串之前,您希望数组中的每个字符串仅被使用一次,而不是过滤掉包含重复字符串的数组。
以下是一个使用 Fisher-Yates 洗牌算法的函数:
/** @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存储每组相关字符串,而不是将它们存储在单独的数组中。


以前不知道它被称为“费舍尔-耶茨洗牌算法”。我一直把它称为“随机排列”。这是一个很好的半随机算法,可以轻松确保每个项目只被遍历一次。 - Oli

2

使用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"];

2
不需要输入那么多。要对数组进行随机排序,只需使用随机比较器进行排序即可:
#include <stdlib.h>

NSInteger shuffleCmp(id a, id b, void* c)
{
    return (arc4random() & 1) ? NSOrderedAscending : NSOrderedDescending;
}

NSArray* shuffled = [original sortedArrayUsingFunction:shuffleCmp context:0];

抱歉挖掘过去,但这是一个糟糕的想法:http://www.cocoawithlove.com/2010/06/sorting-nsmutablearray-with-random.html - warrenm

1
你可以将数组复制到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++)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接