开发者

Reading random values from an array

I have an array with a 14 strings. I want to display each of these 14 strings to the user without duplicates. The closest I got was creating an array of integers and shuffling their values, and then reading from the array of strings using one of the numbers from the int array as the index:

    //appDelegate.randomRiddles 开发者_C百科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"];

But my way is causing crashing and duplicates. Oh and each time I read a value from the strings array, that string is removed from the array making its count decrease by 1. So that complicates this a little bit.


Get the elements in your array like this:

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

This way even though count decreases by one, that is ok, as you will still get a valid next position value till there aren't any more posible values.


By "without duplicates" I assume you mean that you want to use each string in the array once before you use the same string again, not that you want to filter the array so it doesn't contain duplicate strings.

Here's a function that uses a 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
}

If you want to keep the relationship between the riddles, hints, and questions then I'd recommend using a NSDictionary to store each set of related strings rather than storing them in separate arrays.


This task is very easy using an NSMutableArray. In order to do this, simply remove a random element from the array, display it to the user.

Declare a mutable array as an instance variable

NSMutableArray * questions;

When the app launches, populate with values from myArray

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

Then, to get a random element from the array and remove it, do this:

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


No need to type that much. To shuffle an array, you just sort it with random comparator:

#include <stdlib.h>

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

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


You could copy the array into an NSMutableArray and shuffle that. A simple demonstration of how to shuffle an array:

#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;
}

Note that all arrays and numbers here are autoreleased, but in your code you might have to take care of memory management.

If you don't have to keep the elements in the array, you can simplify that (see Oscar Gomez' answer too):

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

At the end, shuffled will be empty. You will have to change the loop conditions too:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜