Supposons que j'ai un tableau et que je veuille choisir un élément au hasard.
Quelle serait la manière la plus simple de procéder?
La manière la plus évidente serait array[random index]
. Mais peut-être qu'il y a quelque chose comme le ruby array.sample
? Ou sinon, une telle méthode pourrait-elle être créée en utilisant une extension?
array[random number from 0 to length-1]
, mais je ne trouve pas comment générer un int aléatoire en swift, je le demanderais en cas de débordement de pile si je n'étais pas bloqué :) Je ne voulais pas polluer la question avec des demi-solutions alors qu'il y en a peut-être quelque chose comme ruby'sarray.sample
Réponses:
Swift 4.2 et supérieur
La nouvelle approche recommandée est une méthode intégrée du protocole Collection:
randomElement()
. Il renvoie un optionnel pour éviter le cas vide que j'ai supposé précédemment.let array = ["Frodo", "Sam", "Wise", "Gamgee"] print(array.randomElement()!) // Using ! knowing I have array.count > 0
Si vous ne créez pas le tableau et que le nombre n'est pas garanti> 0, vous devez faire quelque chose comme:
if let randomElement = array.randomElement() { print(randomElement) }
Swift 4.1 et inférieur
Juste pour répondre à votre question, vous pouvez le faire pour obtenir une sélection aléatoire de tableaux:
let array = ["Frodo", "sam", "wise", "gamgee"] let randomIndex = Int(arc4random_uniform(UInt32(array.count))) print(array[randomIndex])
Les moulages sont laids, mais je pense qu'ils sont nécessaires à moins que quelqu'un d'autre ne le fasse autrement.
la source
man arc4random
- vous et stackoverflow.com/questions/10984974/…removeRandomElement()
fonction en plus derandomElement()
. Il serait modelé surremoveFirst()
, mais supprimera un objet à un index aléatoire.0..<array.count
(pour plusieurs raisons, les principales étant que cela ne fonctionne pas pour les tranches, et qu'il est sujet aux erreurs). Vous pouvez fairelet randomIndex = array.indices.randomElement()
, suivi delet randomElement = array.remove(at: randomIndex)
. Vous pouvez même l'intégrer àlet randomElement = array.remove(at: array.indices.randomElement())
.En reprenant ce que Lucas a dit, vous pouvez créer une extension de la classe Array comme ceci:
extension Array { func randomItem() -> Element? { if isEmpty { return nil } let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] } }
Par exemple:
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16] let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
la source
T
a été renommé enElement
.guard
vérifier si le tableau est vide, puis revenirnil
.arc4random
fait des gains de performance complètement insignifiants. J'ai mis à jour la réponse.Version Swift 4 :
extension Collection where Index == Int { /** Picks a random element of the collection. - returns: A random element of the collection. */ func randomElement() -> Iterator.Element? { return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))] } }
la source
startIndex != 0
Dans Swift 2.2, cela peut être généralisé afin que nous ayons:
UInt.random UInt8.random UInt16.random UInt32.random UInt64.random UIntMax.random // closed intervals: (-3...3).random (Int.min...Int.max).random // and collections, which return optionals since they can be empty: (1..<4).sample [1,2,3].sample "abc".characters.sample ["a": 1, "b": 2, "c": 3].sample
Tout d'abord, implémenter la
random
propriété statique pourUnsignedIntegerType
s:import Darwin func sizeof <T> (_: () -> T) -> Int { // sizeof return type without calling return sizeof(T.self) } let ARC4Foot: Int = sizeof(arc4random) extension UnsignedIntegerType { static var max: Self { // sadly `max` is not required by the protocol return ~0 } static var random: Self { let foot = sizeof(Self) guard foot > ARC4Foot else { return numericCast(arc4random() & numericCast(max)) } var r = UIntMax(arc4random()) for i in 1..<(foot / ARC4Foot) { r |= UIntMax(arc4random()) << UIntMax(8 * ARC4Foot * i) } return numericCast(r) } }
Alors, pour
ClosedInterval
s avecUnsignedIntegerType
bornes:extension ClosedInterval where Bound : UnsignedIntegerType { var random: Bound { guard start > 0 || end < Bound.max else { return Bound.random } return start + (Bound.random % (end - start + 1)) } }
Puis (un peu plus compliqué), pour
ClosedInterval
s avec desSignedIntegerType
limites (en utilisant les méthodes d'aide décrites plus loin):extension ClosedInterval where Bound : SignedIntegerType { var random: Bound { let foot = sizeof(Bound) let distance = start.unsignedDistanceTo(end) guard foot > 4 else { // optimisation: use UInt32.random if sufficient let off: UInt32 if distance < numericCast(UInt32.max) { off = UInt32.random % numericCast(distance + 1) } else { off = UInt32.random } return numericCast(start.toIntMax() + numericCast(off)) } guard distance < UIntMax.max else { return numericCast(IntMax(bitPattern: UIntMax.random)) } let off = UIntMax.random % (distance + 1) let x = (off + start.unsignedDistanceFromMin).plusMinIntMax return numericCast(x) } }
... où
unsignedDistanceTo
,unsignedDistanceFromMin
etplusMinIntMax
les méthodes d'assistance peuvent être implémentées comme suit:extension SignedIntegerType { func unsignedDistanceTo(other: Self) -> UIntMax { let _self = self.toIntMax() let other = other.toIntMax() let (start, end) = _self < other ? (_self, other) : (other, _self) if start == IntMax.min && end == IntMax.max { return UIntMax.max } if start < 0 && end >= 0 { let s = start == IntMax.min ? UIntMax(Int.max) + 1 : UIntMax(-start) return s + UIntMax(end) } return UIntMax(end - start) } var unsignedDistanceFromMin: UIntMax { return IntMax.min.unsignedDistanceTo(self.toIntMax()) } } extension UIntMax { var plusMinIntMax: IntMax { if self > UIntMax(IntMax.max) { return IntMax(self - UIntMax(IntMax.max) - 1) } else { return IntMax.min + IntMax(self) } } }
Enfin, pour toutes les collections où
Index.Distance == Int
:extension CollectionType where Index.Distance == Int { var sample: Generator.Element? { if isEmpty { return nil } let end = UInt(count) - 1 let add = (0...end).random let idx = startIndex.advancedBy(Int(add)) return self[idx] } }
... qui peut être un peu optimisé pour les entiers
Range
s:extension Range where Element : SignedIntegerType { var sample: Element? { guard startIndex < endIndex else { return nil } let i: ClosedInterval = startIndex...endIndex.predecessor() return i.random } } extension Range where Element : UnsignedIntegerType { var sample: Element? { guard startIndex < endIndex else { return nil } let i: ClosedInterval = startIndex...endIndex.predecessor() return i.random } }
la source
Vous pouvez également utiliser la fonction random () intégrée de Swift pour l'extension:
extension Array { func sample() -> Element { let randomIndex = Int(rand()) % count return self[randomIndex] } } let array = [1, 2, 3, 4] array.sample() // 2 array.sample() // 2 array.sample() // 3 array.sample() // 3 array.sample() // 1 array.sample() // 1 array.sample() // 3 array.sample() // 1
la source
Une autre suggestion Swift 3
private extension Array { var randomElement: Element { let index = Int(arc4random_uniform(UInt32(count))) return self[index] } }
la source
Les autres répondent mais avec le support Swift 2.
Swift 1.x
extension Array { func sample() -> T { let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] } }
Swift 2.x
extension Array { func sample() -> Element { let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] } }
Par exemple:
let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31] let randomSample = arr.sample()
la source
Une implémentation fonctionnelle alternative avec vérification du tableau vide.
func randomArrayItem<T>(array: [T]) -> T? { if array.isEmpty { return nil } let randomIndex = Int(arc4random_uniform(UInt32(array.count))) return array[randomIndex] } randomArrayItem([1,2,3])
la source
Voici une extension sur les tableaux avec une vérification de tableau vide pour plus de sécurité:
extension Array { func sample() -> Element? { if self.isEmpty { return nil } let randomInt = Int(arc4random_uniform(UInt32(self.count))) return self[randomInt] } }
Vous pouvez l'utiliser aussi simple que ceci :
let digits = Array(0...9) digits.sample() // => 6
Si vous préférez un Framework qui possède également des fonctionnalités plus pratiques, consultez HandySwift . Vous pouvez l'ajouter à votre projet via Carthage puis l'utiliser exactement comme dans l'exemple ci-dessus:
import HandySwift let digits = Array(0...9) digits.sample() // => 8
De plus, il comprend également une option pour obtenir plusieurs éléments aléatoires à la fois :
digits.sample(size: 3) // => [8, 0, 7]
la source
Swift 3
importer GameKit
func getRandomMessage() -> String { let messages = ["one", "two", "three"] let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count) return messages[randomNumber].description }
la source
Swift 3 - simple et facile à utiliser.
Créer un tableau
var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
Créer une couleur aléatoire
let randomColor = arc4random() % UInt32(arrayOfColors.count)
Définissez cette couleur sur votre objet
your item = arrayOfColors[Int(randomColor)]
Voici un exemple d'un
SpriteKit
projet mettant à jour unSKLabelNode
avec un aléatoireString
:let array = ["one","two","three","four","five"] let randomNumber = arc4random() % UInt32(array.count) let labelNode = SKLabelNode(text: array[Int(randomNumber)])
la source
Si vous souhaitez pouvoir extraire plus d'un élément aléatoire de votre tableau sans doublons , GameplayKit vous a couvert:
import GameplayKit let array = ["one", "two", "three", "four"] let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array) let firstRandom = shuffled[0] let secondRandom = shuffled[1]
Vous avez plusieurs choix pour le caractère aléatoire, voir GKRandomSource :
la source
Je trouve que l'utilisation de GKRandomSource.sharedRandom () de GameKit fonctionne le mieux pour moi.
import GameKit let array = ["random1", "random2", "random3"] func getRandomIndex() -> Int { let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count) return randomNumber
ou vous pouvez renvoyer l'objet à l'index aléatoire sélectionné. Assurez-vous que la fonction renvoie d'abord une chaîne, puis renvoyez l'index du tableau.
return array[randomNumber]
Bref et au point.
la source
Il existe
Collection
maintenant une méthode intégrée :let foods = ["🍕", "🍔", "🍣", "🍝"] let myDinner = foods.randomElement()
Si vous souhaitez extraire jusqu'à
n
des éléments aléatoires d'une collection, vous pouvez ajouter une extension comme celle-ci:extension Collection { func randomElements(_ count: Int) -> [Element] { var shuffledIterator = shuffled().makeIterator() return (0..<count).compactMap { _ in shuffledIterator.next() } } }
Et si vous voulez qu'ils soient uniques, vous pouvez utiliser a
Set
, mais les éléments de la collection doivent être conformes auHashable
protocole:extension Collection where Element: Hashable { func randomUniqueElements(_ count: Int) -> [Element] { var shuffledIterator = Set(shuffled()).makeIterator() return (0..<count).compactMap { _ in shuffledIterator.next() } } }
la source
Dernier code swift3, essayez-le fonctionne bien
let imagesArray = ["image1.png","image2.png","image3.png","image4.png"] var randomNum: UInt32 = 0 randomNum = arc4random_uniform(UInt32(imagesArray.count)) wheelBackgroundImageView.image = UIImage(named: imagesArray[Int(randomNum)])
la source
J'ai trouvé une façon très différente de le faire en utilisant les nouvelles fonctionnalités introduites dans Swift 4.2.
// 👇🏼 - 1 public func shufflePrintArray(ArrayOfStrings: [String]) -> String { // - 2 let strings = ArrayOfStrings //- 3 var stringans = strings.shuffled() // - 4 var countS = Int.random(in: 0..<strings.count) // - 5 return stringans[countS] }
nous avons déclaré une fonction avec des paramètres prenant un tableau de chaînes et retournant une chaîne.
Ensuite, nous prenons les ArrayOfStrings dans une variable.
Il s'agit essentiellement de mélanger le tableau de chaînes, puis de choisir au hasard le nombre du nombre total de comptages, puis de renvoyer l'index aléatoire du tableau mélangé.
la source