Jeśli masz NSMutableArray
, jak losowo tasujesz elementy?
(Mam na to własną odpowiedź, która jest zamieszczona poniżej, ale jestem nowy w Cocoa i chcę wiedzieć, czy jest lepszy sposób).
Aktualizacja: Jak zauważył @Mukesh, od iOS 10+ i macOS 10.12+ istnieje -[NSMutableArray shuffledArray]
metoda, której można użyć do losowego odtwarzania . Szczegółowe informacje można znaleźć na stronie https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc . (Należy jednak pamiętać, że tworzy to nową tablicę zamiast tasowania elementów w miejscu).
objective-c
cocoa
shuffle
Kristopher Johnson
źródło
źródło
for (NSUInteger i = self.count; i > 1; i--) [self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
API
polega na tym, że zwraca nowy,Array
który adresuje do nowej lokalizacji w pamięci.Odpowiedzi:
Nie potrzebujesz metody swapObjectAtIndex. exchangeObjectAtIndex: withObjectAtIndex: już istnieje.
źródło
Rozwiązałem to, dodając kategorię do NSMutableArray.
Edycja: Usunięto niepotrzebną metodę dzięki odpowiedzi Ladda.
Edytuj: zmieniono
(arc4random() % nElements)
naarc4random_uniform(nElements)
dzięki dzięki odpowiedzi Gregory'ego Goltsova i komentarzom Miho i blahdiblahaEdycja: Ulepszenie pętli dzięki komentarzowi Rona
Edycja: Dodano sprawdzenie, czy tablica nie jest pusta, dzięki komentarzowi Mahesha Agrawala
źródło
arc4random_uniform(nElements)
zamiastarc4random()%nElements
. Aby uzyskać więcej informacji, zobacz stronę podręcznika użytkownika arc4random i wyjaśnienie błędu modulo .Ponieważ nie mogę jeszcze komentować, pomyślałem, że udzielę pełnej odpowiedzi. Zmodyfikowałem implementację Kristophera Johnsona dla mojego projektu na wiele sposobów (naprawdę starając się, aby była jak najbardziej zwięzła), jednym z nich jest
arc4random_uniform()
to, że unika modulo stronniczości .źródło
[self count]
(getter właściwości) dwa razy podczas każdej iteracji przez pętlę. Myślę, że wyprowadzenie go z pętli jest warte utraty zwięzłości.[object method]
zamiastobject.method
: ludzie zapominają, że później nie jest tak tanie, jak dostęp do członka struktury, wiąże się to z kosztem wywołania metody ... bardzo źle w pętli.Jeśli zaimportujesz
GameplayKit
, istniejeshuffled
interfejs API:https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled
źródło
shuffledArray = [array shuffledArray];
GameplayKit
więc musisz ją zaimportować.Nieco ulepszone i zwięzłe rozwiązanie (w porównaniu do najlepszych odpowiedzi).
Algorytm jest taki sam i jest opisany w literaturze jako „ Shuffle Fishera-Yatesa ”.
W celu C:
W Swift 3.2 i 4.x:
W Swift 3.0 i 3.1:
Uwaga: Bardziej zwięzłe rozwiązanie w Swift jest możliwe z iOS10 przy użyciu
GameplayKit
.Uwaga: Dostępny jest również algorytm niestabilnego tasowania (ze wszystkimi pozycjami zmuszonymi do zmiany, jeśli liczba> 1)
źródło
Jest to najprostszy i najszybszy sposób przetasowania tablic NSArrays lub NSMutableArrays (puzzle obiektowe to NSMutableArray, zawiera obiekty logiczne. Dodałem do indeksu zmiennych obiektu logicznego, który wskazuje początkową pozycję w tablicy)
dane wyjściowe dziennika:
równie dobrze możesz porównać obj1 z obj2 i zdecydować, jakie wartości chcesz zwrócić:
źródło
Istnieje dobra popularna biblioteka, która ma tę metodę jako część, o nazwie SSToolKit w GitHub . Plik NSMutableArray + SSToolkitAdditions.h zawiera metodę losową. Możesz go również użyć. Wśród nich wydaje się, że jest mnóstwo przydatnych rzeczy.
Strona główna tej biblioteki jest tutaj .
Jeśli tego użyjesz, twój kod będzie wyglądał następująco:
Ta biblioteka ma również kapsułę (patrz CocoaPods)
źródło
W iOS 10 możesz używać NSArray
shuffled()
z GameplayKit . Oto pomocnik dla Array w Swift 3:źródło
Jeśli elementy mają powtórzenia.
np. tablica: AAABB lub BBAAA
jedynym rozwiązaniem jest: ABABA
sequenceSelected
jest NSMutableArray, który przechowuje elementy klasy obj, które są wskaźnikami do jakiejś sekwencji.źródło
static
zapobiega pracy w wielu instancjach: byłoby znacznie bezpieczniej i czytelniej korzystać z dwóch metod, głównej, która tasuje i wywołuje metodę drugorzędną, podczas gdy metoda wtórna wywołuje samą siebie i nigdy nie przetasowuje. Jest też błąd ortograficzny.źródło
arc4random_uniform([theArray count])
byłoby jeszcze lepiej, jeśli jest dostępna w obsługiwanej wersji Mac OS X lub iOS.Odpowiedź Kristophera Johnsona jest całkiem ładna, ale nie jest całkowicie losowa.
Biorąc pod uwagę tablicę 2 elementów, funkcja ta zawsze zwraca tablicę odwróconą, ponieważ generujesz zakres swojej losowości na pozostałych indeksach.
shuffle()
Byłaby bardziej dokładna funkcjaźródło
i < (count-1)
.)Edycja: Niepoprawne.W celach informacyjnych nie usunąłem tego postu. Zobacz komentarze na temat powodów, dla których to podejście jest nieprawidłowe.
Prosty kod tutaj:
źródło