स्विफ्ट ऐरे - जांचें कि क्या कोई इंडेक्स मौजूद है


140

स्विफ्ट में, क्या यह जांचने का कोई तरीका है कि क्या एक इंडेक्स एक सरणी में मौजूद है जिसमें एक घातक त्रुटि डाली जा रही है?

मुझे उम्मीद थी कि मैं ऐसा कुछ कर सकता हूं:

let arr: [String] = ["foo", "bar"]
let str: String? = arr[1]
if let str2 = arr[2] as String? {
    // this wouldn't run
    println(str2)
} else {
    // this would be run
}

लेकिन मुझे मिलता है

घातक त्रुटि: एरे इंडेक्स को सीमा से बाहर

जवाबों:


442

स्विफ्ट में एक सुंदर तरीका:

let isIndexValid = array.indices.contains(index)

10
वास्तविक जीवन में, यह बात नहीं होनी चाहिए, लेकिन समय-जटिलता-वार यह उपयोग करने के लिए बेहतर नहीं होगा index < array.count?
फंक्शनल 7

2
मैं ईमानदारी से सोचता हूं कि आपके द्वारा दिया गया उदाहरण थोड़ा विवादित है क्योंकि मैंने कभी भी नकारात्मक सूचकांक मूल्य का अनुभव नहीं किया है, लेकिन अगर वास्तव में ऐसा होना चाहिए, तो दो सच / झूठे चेक अभी भी बेहतर होंगे: यानी index >= 0 && index < array.countसबसे खराब स्थिति के बजाय n तुलना।
फंक्शनल 7

13
यदि आपको आश्चर्य होता है कि गति का अंतर क्या है, तो मैंने इसे Xcode के उपकरणों के साथ मापा और यह नगण्य है। gist.github.com/masonmark/a79bfa1204c957043687f4bdaef0c2ad
मेसन

7
यह सही है, इस पर एक और बिंदु जोड़ने के लिए: यदि आप एक ही तर्क को लागू करते हैं ArraySlice, तो पहला इंडेक्स 0 नहीं होगा, इसलिए ऐसा index >= 0करना एक अच्छा-पर्याप्त चेक नहीं होगा। .indicesइसके बजाय किसी भी मामले में काम करता है।
DeFrenZ

2
मुझे इसके लिए स्विफ्ट बहुत पसंद है। यहां मेरा उपयोग मामला है: सेवा के लिए चमकदार JSON संरचना का निर्माण करना था इसलिए ऐसा करना पड़ा: "attendee3": names.indices.contains (2)? नाम [2]: ""
ली प्रॉबर्ट

64

प्रकार विस्तार:

extension Collection {

    subscript(optional i: Index) -> Iterator.Element? {
        return self.indices.contains(i) ? self[i] : nil
    }

}

इसका उपयोग करने पर आपको एक वैकल्पिक मान वापस मिलता है जब कीवर्ड को अपने सूचकांक में वैकल्पिक रूप से जोड़ते हैं जिसका अर्थ है कि आपका प्रोग्राम दुर्घटनाग्रस्त नहीं होता है भले ही सूचकांक सीमा से बाहर हो। आपके उदाहरण में:

let arr = ["foo", "bar"]
let str1 = arr[optional: 1] // --> str1 is now Optional("bar")
if let str2 = arr[optional: 2] {
    print(str2) // --> this still wouldn't run
} else {
    print("No string found at that index") // --> this would be printed
}

4
उत्कृष्ट उत्तर 👏 optionalपैरामीटर में उपयोग करते समय सबसे महत्वपूर्ण यह पठनीय है । धन्यवाद!
जकूब

2
Awesomeness: डी ने मेरा दिन बचाया।
कोडेटर्ड

2
यह सुंदर है
जोगलिंड

32

बस जांचें कि क्या इंडेक्स सरणी आकार से कम है:

if 2 < arr.count {
    ...
} else {
    ...
}

3
यदि सरणी का आकार अज्ञात है तो क्या होगा?
नाथन मैककस्ले

8
@NathanMcKaskle सरणी को हमेशा पता होता है कि इसमें कितने तत्व हैं, इसलिए आकार अज्ञात नहीं हो सकता है
एंटोनियो

16
क्षमा करें, मैं वहां नहीं सोच रहा था। मॉर्निंग कॉफी अभी भी रक्तप्रवाह में प्रवेश कर रही थी।
नाथन मैककस्ले

4
@NathanMcKaskle कोई चिंता नहीं ... कभी-कभी कई कॉफ़ी के बाद भी मेरे साथ ऐसा होता है ;-)
एंटोनियो

कुछ मायनों में, यह सबसे अच्छा जवाब है, क्योंकि यह ओ (एन) के बजाय ओ (1) में चलता है।
स्कॉट्टीब्लाड्स

12

कुछ विस्तार चीनी जोड़ें:

extension Collection {
  subscript(safe index: Index) -> Iterator.Element? {
    guard indices.contains(index) else { return nil }
    return self[index]
  }
}

if let item = ["a", "b", "c", "d"][safe: 3] { print(item) }//Output: "d"
//or with guard:
guard let anotherItem = ["a", "b", "c", "d"][safe: 3] else {return}
print(anotherItem) // "d"

if letसरणियों के साथ संयोजन में स्टाइल कोडिंग करते समय पठनीयता को बढ़ाता है


2
ईमानदारी से, यह अधिक से अधिक पठनीयता और स्पष्टता के साथ करने का सबसे आसान तरीका है
Barndog

1
@barndog इसे भी प्यार करते हैं। मैं आमतौर पर इसे किसी भी परियोजना में शुगर के रूप में जोड़ता हूं। साथ ही गार्ड उदाहरण भी जोड़ा। इस एक के साथ आने के लिए तेजी से सुस्त समुदाय के लिए क्रेडिट।
इओनिस्ट

अच्छा समाधान ... लेकिन आउटपुट "d" को
छपेगा

यह स्विफ्ट भाषा का हिस्सा होना चाहिए। सीमा से बाहर सूचकांक का मुद्दा शून्य मानों से कम समस्याग्रस्त नहीं है। मैं भी इसी तरह के वाक्यविन्यास का उपयोग करने का सुझाव दूंगा: शायद कुछ इस तरह: myArray [? 3]। अगर MyArray वैकल्पिक है, तो आप myArray प्राप्त करेंगे? [? 3]
एंडी वीनस्टीन

@ और वेन्स्टीन आपको इसे सेब
on

7

आप इसे सरणी के आकार की जांच करने के लिए एक सुरक्षित तरीके से फिर से लिख सकते हैं, और एक टर्नरी सशर्त का उपयोग कर सकते हैं:

if let str2 = (arr.count > 2 ? arr[2] : nil) as String?

1
एंटोनियो का सुझाव है कि बहुत अधिक पारदर्शी (और कुशल) है जहां टर्नरी उपयुक्त होगा यदि आपके पास उपयोग करने के लिए आसानी से उपलब्ध मूल्य है और यदि पूरी तरह से समाप्त करने के लिए, तो केवल एक बयान छोड़ दें।
डेविड बेरी

1
@ डेविड ने बताया कि एंटोनियो को मूल कोड में ifएक ifबयान के बजाय दो कथनों की आवश्यकता है । मेरा कोड ifएक सशर्त ऑपरेटर के साथ दूसरे की जगह लेता है , जिससे आपको elseदो अलग-अलग elseब्लॉकों को मजबूर करने के बजाय एक रखने की सुविधा मिलती है ।
dasblinkenlight 15

1
मैं दो नहीं देख रहा हूँ अगर उसके कोड में स्टेटमेंट्स डालते हैं, तो उसे अपने इलिप्सिस के लिए str2 = arrest [1] दें और यह हो गया। यदि आप ओपी को प्रतिस्थापित करते हैं यदि स्टेटमेंट को एंटोनियो के इफ स्टेटमेंट के साथ दिया जाए, और असाइनमेंट को अंदर ले जाएं (या नहीं, क्योंकि str2 का एकमात्र उपयोग यह प्रिंट करना है, तो इसकी कोई आवश्यकता नहीं है, बस प्रिंटलेन में डीफेरेंस इनलाइन डालें। उल्लेख नहीं है। कि टर्नरी ऑपरेटर सिर्फ एक अस्पष्ट है (कुछ :)) अगर / तो। अगर गिरफ्तार किया जाए। गिनती> 2, फिर गिरफ्तारी [2] कभी शून्य नहीं हो सकती है, इसलिए इसे स्ट्रिंग में मैप क्यों करें? बस अगर आप अभी तक एक और बयान कर सकते हैं।
डेविड बेरी

@ डेविड ifओपी के सवाल से पूरी तरह से एंटोनियो के जवाब की "तब" शाखा के अंदर समाप्त हो जाएगा, इसलिए दो नेस्टेड ifएस होंगे। मैं ओपीएस कोड को एक छोटे से उदाहरण के रूप में देख रहा हूं, इसलिए मैं यह मान रहा हूं कि वह अभी भी एक चाहते हैं if। मैं आपसे सहमत हूं कि उनके उदाहरण ifमें यह आवश्यक नहीं है। लेकिन फिर से, पूरा बयान व्यर्थ है, क्योंकि ओपी जानता है कि सरणी की लंबाई पर्याप्त नहीं है, और इसका कोई भी तत्व नहीं है nil, इसलिए वह ifकेवल अपने elseब्लॉक को हटा सकता है और रख सकता है ।
दासब्लिंकलाइटलाइट

नहीं, यह नहीं होगा। एंटोनियो अगर ओपी के बयान को बदल देता है। चूंकि सरणी प्रकार [स्ट्रिंग] है, आप जानते हैं कि इसमें कभी भी एक शून्य नहीं हो सकता है, इसलिए लंबाई से परे कुछ भी जांचने की आवश्यकता नहीं है।
डेविड बेरी

7

स्विफ्ट 4 एक्सटेंशन:

मेरे लिए मैं विधि की तरह पसंद करता हूं।

// MARK: - Extension Collection

extension Collection {

    /// Get at index object
    ///
    /// - Parameter index: Index of object
    /// - Returns: Element at index or nil
    func get(at index: Index) -> Iterator.Element? {
        return self.indices.contains(index) ? self[index] : nil
    }
}

@Benno Kress को धन्यवाद


1

यदि कोई ऐरे इंडेक्स मौजूद है:

यदि आप एक्सटेंशन शुगर नहीं जोड़ना चाहते हैं तो यह पद्धति बहुत अच्छी है:

let arr = [1,2,3]
if let fourthItem = (3 < arr.count ?  arr[3] : nil ) {
     Swift.print("fourthItem:  \(fourthItem)")
}else if let thirdItem = (2 < arr.count ?  arr[2] : nil) {
     Swift.print("thirdItem:  \(thirdItem)")
}
//Output: thirdItem: 3

1
extension Array {
    func isValidIndex(_ index : Int) -> Bool {
        return index < self.count
    }
}

let array = ["a","b","c","d"]

func testArrayIndex(_ index : Int) {

    guard array.isValidIndex(index) else {
        print("Handle array index Out of bounds here")
        return
    }

}

यह indexOutOfBounds को संभालने के लिए मेरे लिए काम करता है


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