Si tienes un NSMutableArray
, ¿cómo barajas los elementos al azar?
(Tengo mi propia respuesta para esto, que se publica a continuación, pero soy nuevo en Cocoa y estoy interesado en saber si hay una mejor manera).
Actualización: Como señaló @Mukesh, a partir de iOS 10+ y macOS 10.12+, hay un -[NSMutableArray shuffledArray]
método que puede usarse para barajar. Consulte https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc para más detalles. (Pero tenga en cuenta que esto crea una nueva matriz, en lugar de barajar los elementos en su lugar).
objective-c
cocoa
shuffle
Kristopher Johnson
fuente
fuente
for (NSUInteger i = self.count; i > 1; i--) [self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
API
es que devuelve un nuevoArray
que se dirige a una nueva ubicación en la memoria.Respuestas:
No necesita el método swapObjectAtIndex. exchangeObjectAtIndex: withObjectAtIndex: ya existe.
fuente
Resolví esto agregando una categoría a NSMutableArray.
Editar: Se eliminó el método innecesario gracias a la respuesta de Ladd.
Editar: cambiado
(arc4random() % nElements)
aarc4random_uniform(nElements)
gracias a la respuesta de Gregory Goltsov y los comentarios de miho y blahdiblahEditar: Mejora de bucle, gracias al comentario de Ron
Editar: se agregó la verificación de que la matriz no está vacía, gracias al comentario de Mahesh Agrawal
fuente
arc4random_uniform(nElements)
lugar dearc4random()%nElements
. Consulte la página de manual arc4random y esta explicación del sesgo de módulo para obtener más información.Como todavía no puedo comentar, pensé que contribuiría con una respuesta completa. Modifiqué la implementación de Kristopher Johnson para mi proyecto de varias maneras (realmente tratando de hacerlo lo más conciso posible), una de ellas es
arc4random_uniform()
porque evita el sesgo de módulo .fuente
[self count]
(un captador de propiedades) dos veces en cada iteración a través del bucle. Creo que sacarlo del circuito vale la pena perder la concisión.[object method]
lugar deobject.method
: la gente tiende a olvidar que lo último no es tan barato como acceder a un miembro de estructura, viene con el costo de una llamada al método ... muy malo en un bucle.Si importa
GameplayKit
, hay unashuffled
API:https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled
fuente
shuffledArray = [array shuffledArray];
GameplayKit
lo que debe importarlo.Una solución ligeramente mejorada y concisa (en comparación con las respuestas principales).
El algoritmo es el mismo y se describe en la literatura como " Shuffle Fisher-Yates ".
En el objetivo-C:
En Swift 3.2 y 4.x:
En Swift 3.0 y 3.1:
Nota: Una solución más concisa en Swift es posible desde iOS10 usando
GameplayKit
.Nota: También está disponible un algoritmo para barajar inestable (con todas las posiciones obligadas a cambiar si cuenta> 1)
fuente
Esta es la forma más simple y rápida de barajar NSArrays o NSMutableArrays (el rompecabezas de objetos es un NSMutableArray, contiene objetos de rompecabezas. He agregado al índice variable de objetos de rompecabezas que indica la posición inicial en la matriz)
salida de registro:
también puede comparar obj1 con obj2 y decidir qué desea devolver posibles valores son:
fuente
Hay una buena biblioteca popular, que tiene este método como parte, llamada SSToolKit en GitHub . El archivo NSMutableArray + SSToolkitAdditions.h contiene un método aleatorio. Puedes usarlo también. Entre esto, parece haber toneladas de cosas útiles.
La página principal de esta biblioteca está aquí .
Si usa esto, su código será así:
Esta biblioteca también tiene un Pod (ver CocoaPods)
fuente
Desde iOS 10, puedes usar NSArray
shuffled()
de GameplayKit . Aquí hay un ayudante para Array en Swift 3:fuente
Si los elementos tienen repeticiones.
por ejemplo, matriz: AAABB o BBAAA
La única solución es: ABABA
sequenceSelected
es un NSMutableArray que almacena elementos de la clase obj, que son punteros a alguna secuencia.fuente
static
evita trabajar en varias instancias: sería mucho más seguro y legible usar dos métodos, uno principal que baraja y llama al método secundario, mientras que el método secundario solo se llama a sí mismo y nunca se reorganiza. También hay un error de ortografía.fuente
arc4random_uniform([theArray count])
sería aún mejor, si está disponible en la versión de Mac OS X o iOS que está apoyando.La respuesta de Kristopher Johnson es bastante buena, pero no es totalmente al azar.
Dada una matriz de 2 elementos, esta función devuelve siempre la matriz inversa, porque está generando el rango de su azar sobre el resto de los índices. Una
shuffle()
función más precisa sería comofuente
i < (count-1)
).Editar: esto no es correcto. Para fines de referencia, no eliminé esta publicación. Ver comentarios sobre la razón por la cual este enfoque no es correcto.
Código simple aquí:
fuente