Выбрать случайный элемент из массива
Предположим у меня есть массив и я хочу, чтобы выбрать один элемент наугад.
что было бы самым простым способом сделать это?
очевидный путь был бы array[random index]. Но, возможно, есть что-то вроде Руби array.sample? Или если нет, можно ли создать такой метод с помощью расширения?
14 ответов:
Swift 4.2 и выше
новый рекомендуемый подход-это встроенный метод:
randomElement(). Он возвращает необязательный, чтобы избежать пустого случая, который я предполагал ранее.let array = ["Frodo", "Sam", "Wise", "Gamgee"] print(array.randomElement()!) // Using ! knowing I have array.count > 0если вы не создаете массив и не гарантируете count > 0, вы должны сделать что-то вроде:
if let randomElement = array.randomElement() { print(randomElement) }Swift 4.1 и ниже
просто чтобы ответить на ваш вопрос, вы можете сделать это, чтобы добиться случайного выбора выбор:
let array = ["Frodo", "sam", "wise", "gamgee"] let randomIndex = Int(arc4random_uniform(UInt32(array.count))) print(array[randomIndex])отливки уродливы, но я считаю, что они необходимы, если у кого-то другого нет другого способа.
Риффинг на то, что сказал Лукас, вы можете создать расширение для класса массива следующим образом:
extension Array { func randomItem() -> Element? { if isEmpty { return nil } let index = Int(arc4random_uniform(UInt32(self.count))) return self[index] } }например:
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16] let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
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)))] } }
на Swift 2.2 это можно обобщить так, что мы имеем:
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во-первых, реализации static
randomсобственность заUnsignedIntegerTypes: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) } }затем на
ClosedIntervalСUnsignedIntegerTypeграницы: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)) } }затем (немного сложнее), за
ClosedIntervalСSignedIntegerTypeграницы (с помощью вспомогательных методов, описанных ниже):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) } }... где
unsignedDistanceTo,unsignedDistanceFromMinиplusMinIntMaxвспомогательные методы могут быть реализованы как следует: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) } } }наконец, для всех коллекций, где
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] } }... который можно немного оптимизировать для integer
Ranges: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 } }
вы также можете использовать встроенную функцию random () Swift для расширения:
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
еще одно предложение Swift 3
private extension Array { var randomElement: Element { let index = Int(arc4random_uniform(UInt32(count))) return self[index] } }
после ответа других, но с поддержкой 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] } }например:
let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31] let randomSample = arr.sample()
альтернативная функциональная реализация с проверкой пустого массива.
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])
Swift 3
импорт GameKit
func getRandomMessage() -> String { let messages = ["one", "two", "three"] let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count) return messages[randomNumber].description }
Swift 3-простой простой в использовании.
Создать Массив
var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]Создать Случайный Цвет
let randomColor = arc4random() % UInt32(arrayOfColors.count)установите этот цвет для вашего объекта
your item = arrayOfColors[Int(randomColor)]вот пример обновление
SKLabelNodeслучайныйString:let array = ["one","two","three","four","five"] let randomNumber = arc4random() % UInt32(array.count) let labelNode = SKLabelNode(text: array[Int(randomNumber)])
если вы хотите иметь возможность получить более одного случайного элемента из вашего массива с нет дубликатов, GameplayKit вы охвачены:
import GameplayKit let array = ["one", "two", "three", "four"] let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array) let firstRandom = shuffled[0] let secondRandom = shuffled[1]у вас есть несколько вариантов для рандома, см. GKRandomSource:
The
GKARC4RandomSourceкласс использует алгоритм, аналогичный тому, который используется в семействе arc4random функций C. (Однако экземпляры этого класса не зависят от вызовов функций arc4random.)The
GKLinearCongruentialRandomSourceкласс использует алгоритм, который быстрее, но менее случайный, чем класс GKARC4RandomSource. (В частности, младшие биты генерируемых чисел повторяются чаще, чем старшие биты.) Использовать этот источник, когда производительность более важна, чем надежная непредсказуемость.The
GKMersenneTwisterRandomSourceкласс использует алгоритм, который медленнее, но более случайный, чем класс GKARC4RandomSource. Используйте этот источник, когда важно, чтобы ваше использование случайных чисел не показывало повторения модели и производительность вызывают меньше беспокойства.
Я нахожу с помощью GameKit в GKRandomSource.sharedRandom () работает лучше всего для меня.
import GameKit let array = ["random1", "random2", "random3"] func getRandomIndex() -> Int { let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count) return randomNumberили вы можете вернуть объект по выбранному случайному индексу. Убедитесь, что функция сначала возвращает строку, а затем возвращает индекс массива.
return array[randomNumber]коротко и по делу.
последний код swift3 попробуйте его работает нормально
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)])
Comments