Выберите случайный элемент из массива - программирование

Выберите случайный элемент из массива

Предположим, что у меня есть массив, и я хочу выбрать один элемент наугад.

Каким будет самый простой способ сделать это?

Очевидным способом будет array[random index]. Но, возможно, есть что-то вроде ruby ​​array.sample? Или, если бы такой метод не мог быть создан с помощью расширения?

4b9b3361

Ответ 1

Swift 4.2 и выше

Новый рекомендуемый подход - это встроенный метод протокола сбора данных: randomElement(). Он возвращает необязательный параметр, чтобы избежать пустого регистра, который я предполагал ранее.

let array = ["Frodo", "Sam", "Wise", "Gamgee"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0

Если вы не создали массив и не гарантировали счет> 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])

Кастинги безобразны, но я считаю, что они требуются, если у кого-то еще нет другого пути.

Ответ 2

Повторяя то, что сказал Лукас, вы можете создать расширение для класса Array следующим образом:

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>

Ответ 3

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)))]
    }

}

Ответ 4

В 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

Сначала, реализуя статическое свойство random для UnsignedIntegerType 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)
    }
}

Тогда для 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]
    }
}

... который может быть оптимизирован для целого числа 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
    }
}

Ответ 5

Вы также можете использовать встроенную функцию 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

Ответ 6

Еще одно предложение Swift 3

private extension Array {
    var randomElement: Element {
        let index = Int(arc4random_uniform(UInt32(count)))
        return self[index]
    }
}

Ответ 7

Другие ответят, но с поддержкой 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()

Ответ 8

Альтернативная функциональная реализация с проверкой на пустой массив.

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])

Ответ 9

Здесь расширение на массивах с проверкой пустого массива:

extension Array {
    func sample() -> Element? {
        if self.isEmpty { return nil }
        let randomInt = Int(arc4random_uniform(UInt32(self.count)))
        return self[randomInt]
    }
}

Вы можете использовать его так же просто, как это:

let digits = Array(0...9)
digits.sample() // => 6

Если вы предпочитаете Рамку, у которой также есть несколько более удобных функций, тогда проверьте HandySwift. Вы можете добавить его в свой проект через Carthage, а затем использовать его точно так же, как в приведенном выше примере:

import HandySwift    

let digits = Array(0...9)
digits.sample() // => 8

Кроме того, он также включает в себя возможность сразу получать несколько случайных элементов:

digits.sample(size: 3) // => [8, 0, 7]

Ответ 10

Swift 3

импортировать GameKit

func getRandomMessage() -> String {

    let messages = ["one", "two", "three"]

    let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count)

    return messages[randomNumber].description

}

Ответ 11

Swift 3 - простой в использовании.

  • Создать массив

    var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
    
  • Создать случайный цвет

    let randomColor = arc4random() % UInt32(arrayOfColors.count)
    
  • Установите этот цвет для вашего объекта

    your item = arrayOfColors[Int(randomColor)]
    

Вот пример проекта SpriteKit, обновляющего SKLabelNode со случайным String:

    let array = ["one","two","three","four","five"]

    let randomNumber = arc4random() % UInt32(array.count)

    let labelNode = SKLabelNode(text: array[Int(randomNumber)])

Ответ 12

Если вы хотите получить более одного случайного элемента из своего массива с без дубликатов, 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:

В классе GKARC4RandomSource используется алгоритм, аналогичный алгоритму, используемому в arc4random семействе C-функций. (Однако экземпляры этого класса не зависят от вызовов функций arc4random.)

Класс GKLinearCongruentialRandomSource использует алгоритм, который быстрее, но менее случайный, чем класс GKARC4RandomSource. (В частности, младшие разряды сгенерированных чисел повторяются чаще, чем высокие биты.) Используйте этот источник, когда производительность важнее, чем надежная непредсказуемость.

Класс GKMersenneTwisterRandomSource использует алгоритм, который работает медленнее, но более случайным, чем класс GKARC4RandomSource. Используйте этот источник, когда важно, чтобы ваше использование случайных чисел не отображало повторяющиеся шаблоны и производительность, вызывает меньшую озабоченность.

Ответ 13

Я нахожу использование 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]

Короткая и точка.

Ответ 14

В Collection теперь есть встроенный метод:

let foods = ["🍕", "🍔", "🍣", "🍝"]
let myDinner = foods.randomElement()

Если вы хотите извлечь до n случайных элементов из коллекции, вы можете добавить расширение, подобное этому:

extension Collection {
    func randomElements(_ count: Int) -> [Element] {
        var shuffledIterator = shuffled().makeIterator()
        return (0..<count).compactMap { _ in shuffledIterator.next() }
    }
}

И если вы хотите, чтобы они были уникальными, вы можете использовать Set, но элементы коллекции должны соответствовать протоколу Hashable:

extension Collection where Element: Hashable {
    func randomUniqueElements(_ count: Int) -> [Element] {
        var shuffledIterator = Set(shuffled()).makeIterator()
        return (0..<count).compactMap { _ in shuffledIterator.next() }
    }
}

Ответ 15

Последний код 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)])

Ответ 16

Я нашел совершенно другой способ сделать это, используя новые функции, представленные в 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] 
}


  1. мы объявили функцию с параметрами, которая принимает массив строк и возвращает строку.

  2. Затем мы берем ArrayOfStrings в переменной.

  3. Затем мы вызываем перемешанную функцию и сохраняем ее в переменной. (Поддерживается только в 4.2)
  4. Затем мы объявляем переменную, которая сохраняет перемешанное значение общего числа строк.
  5. Наконец, мы возвращаем перетасованную строку со значением индекса countS.

В основном это тасование массива строк, а также случайный выбор числа от общего числа счетчиков, а затем возвращение случайного индекса перетасованного массива.