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



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



что было бы самым простым способом сделать это?



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

674   14  

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-простой простой в использовании.

  1. Создать Массив

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

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

    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

    Ничего не найдено.