2011-08-12 14 views
7

Mam tablicę z 14 ciągami. Chcę wyświetlić każdy z tych 14 ciągów dla użytkownika bez duplikatów. Najbliższy Dostałem tworząc tablicę liczb całkowitych i tasowanie ich wartości, a następnie odczytu z tablicy ciągów z zastosowaniem jednego z numerów z int tablicy jako wskaźnik:Odczytywanie losowych wartości z tablicy

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

Ale moja droga powoduje zawieszanie i duplikaty. Aha i za każdym razem, gdy czytam wartość z tablicy łańcuchów, ten ciąg jest usuwany z tablicy, co powoduje zmniejszenie liczby o 1. To trochę komplikuje.

Odpowiedz

7

Get elementy macierzy tak:

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

W ten sposób, mimo że liczba zmniejsza się o jeden, to jest ok, jak będzie wciąż ważny następną wartość pozycji do nie więcej są wartości posible.

+0

Ale czy to nie spowodowałoby duplikatów? – Snowman

+1

@Mohabitar, Nie jeśli za każdym razem, gdy go otrzymasz, obiekt jest usuwany z tablicy. –

+0

Czy nie powinno to być 'arc4random()% [myArray count]' podając liczby od 0 do zliczania -1? W przeciwnym razie ostatni element pozostanie ostatnim, a jeśli count = 1, wykonasz 'arc4random()% 0', co nie jest poprawne. A jeśli chcesz usunąć elementy z tablicy, możesz to powiedzieć lub napisać kod, który to robi. –

1

Można skopiować tablicę do NSMutableArray i przetasować ją. Prosta demonstracja jak shuffle tablicy:

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

pamiętać, że wszystkie tablice i numery są tu autoreleased, ale w kodzie może trzeba dbać o zarządzanie pamięcią.

Jeśli nie masz zachować elementy w tablicy, można uprościć, że (patrz odpowiedź Oscar Gómez ma zbyt):

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

Na koniec, tasuje będzie pusta. Trzeba będzie zmienić warunki pętli też:

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

przez „bez duplikatów” Przypuszczam, że to znaczy, że chcesz korzystać każdy ciąg w tablicy raz przed ponownym użyciem tego samego łańcucha, a nie, że chcesz filtruj tablicę, aby nie zawierała duplikatów.

Oto funkcja, która używa 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 
} 

Jeśli chcesz zachować relacje między zagadek, wskazówki, i pytania wtedy polecam użyciu NSDictionary do przechowywania każdego zestawu powiązanych łańcuchów zamiast przechowywać je w osobnych tablicach.

+0

Nie wiedziałem, że to było określane jako "shuffle Fisher-Yates". Zawsze znałem to jako "przypadkowe permutacje". Jest to dobry algorytm pół-losowy, który zapewnia, że ​​tylko raz przejdziesz przez każdy element. – Oli

2

Zadanie to jest bardzo proste przy użyciu NSMutableArray. Aby to zrobić, po prostu usuń losowy element z tablicy i wyświetl go użytkownikowi.

Zadeklaruj zmienny tablicę jako instancja zmiennej

NSMutableArray * questions; 

Gdy uruchamia app, wypełnić wartościami z myArray

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

Następnie, aby uzyskać losowy element z tablicy i usunąć go, zrób to:

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

Nie trzeba pisać za dużo. Aby przetasować tablicę, po prostu posortuj ją losowo porównawczą:

#include <stdlib.h> 

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

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

Przepraszam, że wyrzucam przeszłość, ale to zły pomysł: http://www.cocoawithlove.com/2010/06/sorting-nsmutablearray-with-random.html – warrenm