Wenn Sie eine haben NSMutableArray
, wie mischen Sie die Elemente zufällig?
(Ich habe meine eigene Antwort darauf, die unten veröffentlicht ist, aber ich bin neu bei Cocoa und ich bin interessiert zu wissen, ob es einen besseren Weg gibt.)
Update: Wie von @Mukesh festgestellt, gibt es ab iOS 10+ und macOS 10.12+ eine -[NSMutableArray shuffledArray]
Methode, die zum Mischen verwendet werden kann. Weitere Informationen finden Sie unter https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc . (Beachten Sie jedoch, dass dadurch ein neues Array erstellt wird, anstatt die vorhandenen Elemente zu mischen.)
objective-c
cocoa
shuffle
Kristopher Johnson
quelle
quelle
for (NSUInteger i = self.count; i > 1; i--) [self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
API
ist, dass es eine neueArray
Adresse zurückgibt, die an einen neuen Speicherort im Speicher adressiert.Antworten:
Sie benötigen die swapObjectAtIndex-Methode nicht. exchangeObjectAtIndex: withObjectAtIndex: existiert bereits.
quelle
Ich habe dieses Problem gelöst, indem ich NSMutableArray eine Kategorie hinzugefügt habe.
Bearbeiten: Unnötige Methode dank Antwort von Ladd entfernt.
Bearbeiten: Geändert
(arc4random() % nElements)
zuarc4random_uniform(nElements)
Dank der Antwort von Gregory Goltsov und Kommentaren von Miho und BlahdiblahEdit: Loop-Verbesserung dank Kommentar von Ron
Bearbeiten: Es wurde hinzugefügt, dass das Array nicht leer ist, dank des Kommentars von Mahesh Agrawal
quelle
arc4random_uniform(nElements)
anstelle vonarc4random()%nElements
. Weitere Informationen finden Sie in der Manpage arc4random und in dieser Erklärung zu Modulo Bias .Da ich noch keinen Kommentar abgeben kann, dachte ich, ich würde eine vollständige Antwort beisteuern. Ich habe die Implementierung von Kristopher Johnson für mein Projekt auf verschiedene Weise modifiziert (wirklich versucht, es so präzise wie möglich zu gestalten), unter anderem,
arc4random_uniform()
weil dadurch Modulo-Bias vermieden werden .quelle
[self count]
bei jeder Iteration durch die Schleife zweimal (einen Eigenschafts-Getter) aufrufen . Ich denke, es ist den Verlust der Prägnanz wert, es aus der Schleife zu entfernen.[object method]
anstattobject.method
: Die Leute neigen dazu zu vergessen, dass letzteres nicht so billig ist wie der Zugriff auf ein Strukturelement, sondern mit den Kosten eines Methodenaufrufs verbunden ist ... sehr schlecht in einer Schleife.Wenn Sie importieren
GameplayKit
, gibt es eineshuffled
API:https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled
quelle
shuffledArray = [array shuffledArray];
GameplayKit
sodass Sie sie importieren müssen.Eine leicht verbesserte und prägnante Lösung (im Vergleich zu den Top-Antworten).
Der Algorithmus ist der gleiche und wird in der Literatur als " Fisher-Yates-Shuffle " beschrieben.
In Ziel-C:
In Swift 3.2 und 4.x:
In Swift 3.0 und 3.1:
Hinweis: Eine präzisere Lösung in Swift ist ab iOS10 mit möglich
GameplayKit
.Hinweis: Ein Algorithmus für instabiles Mischen (bei dem alle Positionen geändert werden müssen, wenn die Anzahl> 1 ist) ist ebenfalls verfügbar
quelle
Dies ist der einfachste und schnellste Weg, um NSArrays oder NSMutableArrays zu mischen (Objektpuzzles sind ein NSMutableArray, es enthält Puzzleobjekte. Ich habe den Index der Puzzleobjektvariablen hinzugefügt, der die Anfangsposition im Array angibt.)
Protokollausgabe:
Sie können auch obj1 mit obj2 vergleichen und entscheiden, welche möglichen Werte Sie zurückgeben möchten:
quelle
Es gibt eine nette, beliebte Bibliothek, die diese Methode als Teil hat und SSToolKit in GitHub heißt . Die Datei NSMutableArray + SSToolkitAdditions.h enthält die Shuffle-Methode. Sie können es auch verwenden. Unter diesen scheint es Unmengen nützlicher Dinge zu geben.
Die Hauptseite dieser Bibliothek ist hier .
Wenn Sie dies verwenden, sieht Ihr Code folgendermaßen aus:
Diese Bibliothek hat auch einen Pod (siehe CocoaPods)
quelle
Ab iOS 10 können Sie NSArray
shuffled()
von GameplayKit aus verwenden . Hier ist ein Helfer für Array in Swift 3:quelle
Wenn Elemente Wiederholungen haben.
zB Array: AAABB oder BBAAA
einzige Lösung ist: ABABA
sequenceSelected
ist ein NSMutableArray, das Elemente der Klasse obj speichert, die Zeiger auf eine Sequenz sind.quelle
static
verhindert das Arbeiten an mehreren Instanzen: Es wäre viel sicherer und lesbarer, zwei Methoden zu verwenden, eine Hauptmethode, die die sekundäre Methode mischt und aufruft, während die sekundäre Methode nur sich selbst aufruft und niemals neu mischt. Es gibt auch einen Rechtschreibfehler.quelle
arc4random_uniform([theArray count])
wäre sogar noch besser, wenn es auf der von Ihnen unterstützten Version von Mac OS X oder iOS verfügbar ist.Kristopher Johnsons Antwort ist ziemlich nett, aber nicht völlig zufällig.
Bei einem Array mit 2 Elementen gibt diese Funktion immer das inverse Array zurück, da Sie den Bereich Ihres Zufalls über den Rest der Indizes generieren. Eine genauere
shuffle()
Funktion wäre wiequelle
i < (count-1)
.)Bearbeiten: Dies ist nicht korrekt. Zu Referenzzwecken habe ich diesen Beitrag nicht gelöscht. Siehe Kommentare zum Grund, warum dieser Ansatz nicht korrekt ist.
Einfacher Code hier:
quelle