2015-02-12 11 views
9

स्विफ्ट 1.2 के रूप में (इस समय बीटा के रूप में उपलब्ध) ऐप्पल Set संग्रह प्रकार प्रस्तुत करता है।स्विफ्ट में एक सेट से यादृच्छिक तत्व कैसे प्राप्त करें?

var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5) 

अब मैं इससे बाहर एक यादृच्छिक तत्व प्राप्त करना चाहते हैं:

कहो, मैं की तरह एक सेट है। प्रश्न कैसे है? Setsubscript(Int) प्रदान नहीं करता है जैसे Array करता है। इसके बजाय इसमें subscript(SetIndex<T>) है। लेकिन सबसे पहले, SetIndex<T> में सुलभ प्रारंभिक नहीं हैं (इसलिए, मैं केवल ऑफसेट के साथ एक इंडेक्स नहीं बना सकता), और दूसरी बात यह भी है कि अगर मैं सेट में पहले तत्व के लिए इंडेक्स प्राप्त कर सकता हूं (var startIndex = set.startIndex) तो एकमात्र तरीका एन-वें इंडेक्स तक पहुंच सकते हैं लगातार कॉल के माध्यम से successor() पर जा सकते हैं।

इसलिए, मैं इस समय केवल 2 विकल्प, दोनों बदसूरत और महंगी देख सकते हैं:

  • सरणी (var array = [Int](set)) में सेट कन्वर्ट और उसके सबस्क्रिप्ट का उपयोग करें (जो पूरी तरह से Int स्वीकार करता है); या
  • किसी सेट में पहले तत्व की अनुक्रमणिका प्राप्त करें, एन-वें अनुक्रमणिका प्राप्त करने के लिए successor() विधियों की श्रृंखला को पार करें, और उसके बाद सेट की सबस्क्रिप्ट के माध्यम से संबंधित तत्व पढ़ें।

क्या मुझे किसी अन्य तरीके से याद आती है?

अद्यतन

रूप @rintaro ने कहा, मैं पहले से उपयोग करना चाहिए() फ़ंक्शन तुरंत सूचकांक मैं चाहता हूँ करने के लिए मिलता है। उदा .:

var set = Set<Int>(arrayLiteral: 1, 2, 3, 4, 5) 
let randomOffset = Int(arc4random_uniform(UInt32(set.count))) 
let random = set[advance(set.startIndex, randomOffset)] 

अद्यतन 2

यह पता चला advance() हे (एन), जो अनिवार्य रूप renders यह बस successor() की श्रृंखला से गुजरने के बराबर होने का की जटिलता है।

+0

धन्यवाद @rintaro! यही वह है जिसकी तलाश में मैं हूं। – courteouselk

उत्तर

8

शायद सबसे अच्छा तरीका advance जो आपके लिए successor चलता है:

func randomElementIndex<T>(s: Set<T>) -> T { 
    let n = Int(arc4random_uniform(UInt32(s.count))) 
    let i = advance(s.startIndex, n) 
    return s[i] 
} 

(संपादित करें: हे, आप वास्तव में सवाल से पहले मैं इसे अपने जवाब को जोड़ा गया ... अच्छी तरह से इस जवाब के साथ अपडेट देखा, अभी भी एक अच्छा विचार है और मैंने कुछ भी सीखा।: डी)

आप सूचकांक के बजाय सेट भी चल सकते हैं (यह मेरा पहला विचार था, लेकिन फिर मुझे advance याद आया)।

func randomElement<T>(s: Set<T>) -> T { 
    let n = Int(arc4random_uniform(UInt32(s.count))) 
    for (i, e) in enumerate(s) { 
     if i == n { return e } 
    } 
    fatalError("The above loop must succeed") 
} 
+0

हां। मजेदार हिस्सा यह है कि सेट के मामले में 'अग्रिम() 'जटिलता ओ (एन) है। तो तकनीकी रूप से यह 'उत्तराधिकारी()' की श्रृंखला को पार करने जैसा ही है, यह बस अधिक संक्षिप्त और इरादे से स्पष्ट दिखता है। मैंने ऐप्पल डेवलपर्स फोरम में इसी तरह के सवाल पूछा, और कर्मचारियों से ध्यान दिया => शायद स्विफ्ट के कुछ भावी रिलीज में मैं जो चाहता हूं उसे करने के लिए बेहतर उपकरण होंगे। अभी के लिए मैं शायद 'अग्रिम() 'के साथ रहूंगा। जो सेट मैं उपयोग करूंगा वह उतना बड़ा नहीं है। – courteouselk

+0

अग्रिम विधि अब संकलित नहीं है, एक्सकोड 7 बीटा 6 –

+2

जस्टिन लुईस जो कुछ भी बदल गया है वह यह है कि अब आपको इंडेक्स 'एक्सटेंशन' पर {advancedby (_ :) 'कॉल करना होगा {func randomElement() -> Element {let एन = Int (arc4random_uniform (UInt32 (गिनती))); मैं = startIndex.advancedBy (एन); वापस लौटें [i];}} ' – griotspeak

1

आप तो एक Set से एक 'यादृच्छिक' तत्व चाहते हैं तो आप का उपयोग करें:

/// A member of the set, or `nil` if the set is empty. 
var first: T? { get } 

0 सूचकांक या 1000000 सूचकांक प्राप्त कोई फर्क नहीं पड़ता - वे सभी एक मनमाना वस्तु हैं।

लेकिन, यदि आप हर बार एक संभावित भिन्न तत्व वापस करने के लिए को बार-बार कॉल करना चाहते हैं, तो first बिल फिट नहीं हो सकता है।

+7

यह लगभग समान ही एल्गोरिदम है https://www.xkcd.com/221/ –

+4

और 'एक्स एक्स' के समान ही http://bit.ly/173dqTe – GoZoner

+0

बेशक, आप इसे कैसे बता सकते हैं। प्रथम। 'एन -1 पर चलने, एनथ वापस लौटने' से अलग है? क्या स्विफ्ट गारंटी देता है कि ट्रैवर्स ऑर्डर समय के साथ स्थिर है? कुछ भाषाएं नहीं होती हैं (क्योंकि सेट का हैश मेमोरी एड्रेस पर निर्भर करता है और कचरा एकत्रित सिस्टम में मेमोरी पतों में परिवर्तन होता है)। – GoZoner

5
extension Set { 
    func randomElement() -> Element? { 
     return count == 0 ? nil : self[advance(self.startIndex, Int(arc4random()) % count)] 
    } 
} 
2

ऊपर टिप्पणियों के अनुसार स्विफ्ट अपडेट कर रहे हैं, सेट के लिए एक विस्तार के लिए एक छोटा सा परिवर्तन का प्रयोग किया:

func randomElement() -> Element? 
{ 
    let randomInt = Int(arc4random_uniform(UInt32(self.count))) 
    let index = startIndex.advancedBy(randomInt) 
    return count == 0 ? nil: self[index] 
} 
4

में तेजी से 3

extension Set { 
    public func randomObject() -> Element? { 
     let n = Int(arc4random_uniform(UInt32(self.count))) 
     let index = self.index(self.startIndex, offsetBy: n) 
     return self.count > 0 ? self[index] : nil 
    } 
} 
संबंधित मुद्दे