एक सरणी से एक यादृच्छिक तत्व चुनें


189

मान लीजिए कि मेरे पास एक सरणी है और मैं यादृच्छिक पर एक तत्व चुनना चाहता हूं।

ऐसा करने का सबसे सरल तरीका क्या होगा?

स्पष्ट तरीका होगा array[random index]। लेकिन शायद माणिक की तरह कुछ है array.sample? या यदि एक्सटेंशन का उपयोग करके ऐसी विधि नहीं बनाई जा सकती है?


1
क्या आपने अभी तक कोई अलग तरीका आजमाया है?
ford प्रीफेक्ट

मैं कोशिश करूँगा array[random number from 0 to length-1], लेकिन मैं यह नहीं जान सकता कि स्विफ्ट में एक यादृच्छिक इंट कैसे उत्पन्न होता है, मैं इसे स्टैक ओवरफ्लो पर पूछूंगा यदि मुझे ब्लॉक नहीं किया गया था :) मैं आधे समाधान के साथ सवाल को प्रदूषित नहीं करना चाहता था, जब हो सकता है रूबी की तरह कुछarray.sample
फेला विंकेलमॉल

1
आप ओब्ज-सी
आर्बिटुर

आपके प्रश्न के लिए कोई स्पष्टीकरण नहीं है कि JQuery समकक्ष के रूप में एक ही प्रतिक्रिया क्यों नहीं मिली। लेकिन सामान्य तौर पर, आपको एक प्रश्न पोस्ट करते समय इन दिशानिर्देशों का पालन करना चाहिए। अच्छा सवाल कैसे पूछें? । किसी और से मदद मांगने से पहले एक समाधान निकालने में थोड़ा सा प्रयास करने पर इसे ऐसा बना दें। जब मैं Google "रैंडम नंबर स्विफ्ट का चयन करता हूं", तो पहला पृष्ठ arc4random_uniform का सुझाव देने वाले उत्तरों से भरा होता है। इसके अलावा, RTFD ... "f'ing प्रलेखन पढ़ें"। यह आश्चर्य की बात है कि इस तरह से कितने सवालों के जवाब दिए जा सकते हैं।
ऑस्टिन ए

अपनी तरह की प्रतिक्रिया के लिए धन्यवाद। हां, मुझे लगता है कि मुझे इस सवाल का जवाब खुद देना चाहिए था, लेकिन यह इतना आसान लग रहा था कि किसी और को लगभग मुफ्त प्रतिष्ठा अंक देना अच्छा था। और मैंने इसे तब लिखा था जब एप्पल के आधिकारिक स्विफ्ट डॉक्स भी सार्वजनिक नहीं थे, उस समय निश्चित रूप से Google परिणाम नहीं थे। लेकिन सवाल एक बार -12 पर था, इसलिए मुझे पूरा विश्वास है कि यह आखिरकार सकारात्मक होगा :)
फेला विंकेलमॉलेन

जवाबों:


321

स्विफ्ट 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)
}

स्विफ्ट 4.1 और नीचे

बस अपने प्रश्न का उत्तर देने के लिए, आप यादृच्छिक सरणी चयन को प्राप्त करने के लिए ऐसा कर सकते हैं:

let array = ["Frodo", "sam", "wise", "gamgee"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])

कास्टिंग बदसूरत हैं, लेकिन मेरा मानना ​​है कि वे आवश्यक हैं जब तक कि किसी और के पास कोई दूसरा तरीका न हो।


4
Swift एक Intent रिटर्न जेनरेटर की पेशकश क्यों नहीं करता है? यह 2 लाइन बहुत ही क्रियात्मक लगती है बस यादृच्छिक रूप से चुने गए इंट को वापस करने के लिए। क्या कोई कम्प्यूटेशनल / सिंटैक्टिकल लाभ है जो किसी Int के विपरीत UInt32 को वापस कर सकता है? इसके अलावा, स्विफ्ट इस फ़ंक्शन के लिए एक वैकल्पिक विकल्प क्यों नहीं देता है या उपयोगकर्ता को यह निर्दिष्ट करने की अनुमति देता है कि वे किस प्रकार के पूर्णांक को लौटाएंगे?
ऑस्टिन ए

नोट जोड़ने के लिए, यह यादृच्छिक संख्या जनरेटर विधि "मोडुलो पूर्वाग्रह" को रोक सकती है। देखें man arc4randomऔर stackoverflow.com/questions/10984974/…
Kent Liau

1
@AustinA, स्विफ्ट 4.2 डीओईएस में एक देशी रैंडम नंबर जनरेटर फंक्शन होता है जो उन सभी स्केलर डेटा प्रकारों पर लागू होता है जिनकी आप अपेक्षा कर सकते हैं: Int, Double, Float, UInt32, इत्यादि। और यह आपको मानों के लिए लक्ष्य रेंज प्रदान करने की सुविधा देता है। बेहद सुविधाजनक। आप सरणी का उपयोग कर सकते [Int.random (0 .. <array.count)] `स्विफ्ट 4.2 में
डंकन सी

काश स्विफ्ट 4.2 के removeRandomElement()अलावा भी एक फंक्शन लागू होता randomElement()। इस पर मॉडलिंग की जाएगी removeFirst(), लेकिन किसी वस्तु को यादृच्छिक सूचकांक पर हटा दिया जाएगा।
डंकन सी।

@ डंकन आप से बचना चाहिए 0..<array.count(कई कारणों से, मुख्य यह है कि यह स्लाइस के लिए काम नहीं करता है, और इसकी त्रुटि की संभावना है)। आप कर सकते हैं let randomIndex = array.indices.randomElement(), उसके बाद let randomElement = array.remove(at: randomIndex)। आप इसे इनलाइन भी कर सकते हैं let randomElement = array.remove(at: array.indices.randomElement())
अलेक्जेंडर - मोनिका

137

लुकास ने जो कहा, उस पर भरोसा करते हुए, आप इस तरह के ऐरे वर्ग के लिए एक विस्तार बना सकते हैं:

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>

2
स्विफ्ट में 2 Tका नाम बदल दिया गया है Element
22

25
ध्यान दें कि एक खाली सरणी यहाँ दुर्घटना का कारण
बनेगी

1
@Berik खैर आप एक वैकल्पिक तत्व वापस कर सकते हैं और फिर यह guardदेखने के लिए हमेशा जांच करें कि क्या सरणी खाली है और फिर वापस लौटना है nil
हरीश

1
माना। आउट-ऑफ-बाउंड पर ऐरे क्रैश हो जाता है ताकि वे प्रदर्शन कर सकें। कॉलिंग arc4randomकिसी भी प्रदर्शन लाभ को पूरी तरह से महत्वहीन बना देती है। मैंने जवाब अपडेट कर दिया है।
बेरिक

45

स्विफ्ट 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)))]
    }

}

यह संग्रह पर सीमाओं से बाहर एक सूचकांक के साथ दुर्घटनाग्रस्त हो सकता हैstartIndex != 0
डैन

21

में स्विफ्ट 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:

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:

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

18

आप विस्तार के लिए स्विफ्ट के अंतर्निहित यादृच्छिक () फ़ंक्शन का उपयोग कर सकते हैं:

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

वास्तव में यादृच्छिक () स्टैंडर्ड सी लाइब्रेरी ब्रिजिंग से है, आप इसे और दोस्तों को टर्मिनल में देख सकते हैं, "मैन रैंडम"। लेकिन खुशी है कि आपने उपलब्धता की ओर इशारा किया है!
डेविड एच।

1
यह एक ही यादृच्छिक क्रम को हर बार चलाता है
iTSangar

1
@iTSangar तुम सही हो! रैंड () उपयोग करने के लिए सही है। मेरे उत्तर को अपडेट करना।
नताशाTheRobot

6
यह मोडुलो पूर्वाग्रह के लिए भी अतिसंवेदनशील है।
ऐदन गोमेज़

@mattt ने लिखा यादृच्छिक संख्याएँ उत्पन्न करने पर अच्छा लेख । टीएल; डीआर 4 आर्कगैमैंड परिवार में से कोई एक बेहतर विकल्प है।
इलाइटनॉन

9

एक और स्विफ्ट 3 सुझाव

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

4

दूसरों के जवाब के बाद लेकिन स्विफ्ट 2 समर्थन के साथ।

स्विफ्ट 1.x

extension Array {
    func sample() -> T {
        let index = Int(arc4random_uniform(UInt32(self.count)))
        return self[index]
    }
}

स्विफ्ट 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()

2

खाली सरणी के लिए चेक के साथ एक वैकल्पिक कार्यात्मक कार्यान्वयन।

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

2

यहाँ अधिक सुरक्षा के लिए एक खाली सरणी जाँच के साथ Arrays पर एक एक्सटेंशन दिया गया है :

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

यदि आप एक ऐसी फ्रेमवर्क पसंद करते हैं, जिसमें कुछ अधिक उपयोगी विशेषताएं हैं तो हैंडवाइस लिफ्ट चेकआउट करें । आप इसे Carthage के माध्यम से अपनी परियोजना में जोड़ सकते हैं, फिर इसे ऊपर दिए गए उदाहरण की तरह उपयोग कर सकते हैं:

import HandySwift    

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

इसके अतिरिक्त इसमें एक साथ कई यादृच्छिक तत्व प्राप्त करने का विकल्प भी शामिल है :

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

2

स्विफ्ट 3

गेमकीट आयात करें

func getRandomMessage() -> String {

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

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

    return messages[randomNumber].description

}

2

स्विफ्ट 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)]

एक यादृच्छिक के साथ SpriteKitअद्यतन करने वाली परियोजना का एक उदाहरण यहां दिया गया है :SKLabelNodeString

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

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

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

2

यदि आप डुप्लिकेट के बिना अपने सरणी से एक से अधिक यादृच्छिक तत्व प्राप्त करना चाहते हैं , तो 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 परिवार में कार्यरत के समान उपयोग करता है। (हालांकि, इस वर्ग के उदाहरण कॉल से लेकर आर्क 4 आयामी कार्यों के लिए स्वतंत्र हैं।)

GKLinearCongruentialRandomSourceवर्ग एक एल्गोरिथ्म है कि तेजी से, लेकिन कम यादृच्छिक, GKARC4RandomSource वर्ग से उपयोग करता है। (विशेष रूप से, उत्पन्न संख्याओं के निम्न बिट्स उच्च बिट्स की तुलना में अधिक बार दोहराते हैं।) इस स्रोत का उपयोग तब करें जब प्रदर्शन मजबूत अप्रत्याशितता से अधिक महत्वपूर्ण हो।

GKMersenneTwisterRandomSourceवर्ग, एक एल्गोरिथ्म है कि धीमी है, लेकिन अधिक यादृच्छिक है का उपयोग करता है GKARC4RandomSource वर्ग की तुलना में। इस स्रोत का उपयोग तब करें जब यह महत्वपूर्ण हो कि आपके रैंडम नंबरों का उपयोग दोहराए जाने वाले पैटर्न और प्रदर्शन को कम न दिखाए।


1

मुझे गेमकिट का GKRandomSource.saredRandom () का उपयोग करना सबसे अच्छा लगता है।

import GameKit

let array = ["random1", "random2", "random3"]

func getRandomIndex() -> Int {
    let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count)
    return randomNumber

या आप चयनित यादृच्छिक सूचकांक पर ऑब्जेक्ट को वापस कर सकते हैं। सुनिश्चित करें कि फ़ंक्शन पहले स्ट्रिंग लौटाता है, और फिर सरणी का सूचकांक वापस करता है।

    return array[randomNumber]

संक्षिप्त एवं सटीक।


1

अभी एक अंतर्निहित विधि है 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() }
    }
}

0

लेटेस्ट स्विफ्ट 3 कोड इसे काम करने की कोशिश करता है

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

-2

मैंने स्विफ्ट 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. फिर हम एक वेरिएबल में ऐरेऑफस्ट्रेस लेते हैं ।

  3. फिर हम फेरबदल फ़ंक्शन को कॉल करते हैं और एक चर में संग्रहीत करते हैं। (केवल 4.2 में समर्थित)
  4. फिर हम एक वैरिएबल घोषित करते हैं जो स्ट्रिंग की कुल गणना का एक फेरबदल मूल्य बचाता है।
  5. अंत में हम गिनती के सूचकांक मूल्य पर फेरबदल स्ट्रिंग लौटाते हैं।

यह मूल रूप से स्ट्रिंग्स के सरणी को फेरबदल कर रहा है और फिर गिनती की कुल संख्या की एक यादृच्छिक पिक भी है और फिर फेरबदल सरणी के यादृच्छिक सूचकांक को लौटाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.