स्विफ्ट में एन्यूमरेशन के दौरान ऐरे से निकालना?


86

मैं स्विफ्ट में एक सरणी के माध्यम से गणना करना चाहता हूं, और कुछ वस्तुओं को हटा देना चाहता हूं। मैं सोच रहा था कि यह करना सुरक्षित है, और यदि नहीं, तो मुझे यह कैसे हासिल करना है।

वर्तमान में, मैं यह कर रहा हूँ:

for (index, aString: String) in enumerate(array) {
    //Some of the strings...
    array.removeAtIndex(index)
}

जवाबों:


72

स्विफ्ट 2 में यह प्रयोग करने में काफी आसान है enumerateऔर reverse

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
    a.removeAtIndex(i)
}
print(a)

1
काम करता है लेकिन फ़िल्टर वास्तव में जाने का रास्ता है

13
@ मेयरेज़ झूठी। "मैं स्विफ्ट में एक सरणी के माध्यम से गणना करना चाहता हूं , और कुछ वस्तुओं को हटा सकता हूं ।" filterएक नई सरणी देता है। आप सरणी से कुछ भी नहीं निकाल रहे हैं। मैं भी filterएक गणना नहीं कहूंगा । एक बिल्ली की त्वचा के लिए हमेशा एक से अधिक तरीके होते हैं।
जॉन्सटन

6
कठोरता, मेरा बुरा! पीएलए न त्वचा किसी भी बिल्लियों

56

आप इस पर विचार कर सकते हैं filter:

var theStrings = ["foo", "bar", "zxy"]

// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }

का पैरामीटर filterसिर्फ एक क्लोजर है जो एक सरणी प्रकार का उदाहरण लेता है (इस मामले में String) और रिटर्न ए Bool। जब परिणाम होता है तो trueयह तत्व को रखता है, अन्यथा तत्व को फ़िल्टर किया जाता है।


16
मुझे लगता है कि filterसरणी को अद्यतन नहीं करता है स्पष्ट कर देता हूँ, यह सिर्फ एक नया एक
एंटोनियो

कोष्ठक हटा दिया जाना चाहिए; यह एक अनुगामी बंद है।
जेसी

@Antonio तुम सही हो। वास्तव में यही कारण है कि मैंने इसे एक सुरक्षित समाधान के रूप में पोस्ट किया है। विशाल सरणियों के लिए एक अलग समाधान पर विचार किया जा सकता है।
मैटियो पियोम्बो

हम्म, जैसा कि आप कहते हैं कि यह एक नया सरणी देता है। क्या filterविधि को एक में बनाना संभव है mutating(जैसा कि मैंने पढ़ा है कि mutatingखोजशब्द selfइसके बदले कार्यों को सक्षम बनाता है )?
Gee.E

@ Gee.E निश्चित रूप से आप प्रश्न के कोड के समान और इसे चिह्नित करने पर एक एक्सटेंशन के रूप में एक स्थान फ़िल्टर में जोड़ सकते हैं । वैसे भी विचार करें कि यह हमेशा एक फायदा नहीं हो सकता है। वैसे भी हर बार जब आप किसी वस्तु को हटाते हैं, तो आपके सरणी को स्मृति में पुनर्गठित किया जा सकता है । इस प्रकार यह एक नए सरणी को आवंटित करने में अधिक कुशल हो सकता है और फिर फ़िल्टर फ़ंक्शन के परिणाम के साथ परमाणु प्रतिस्थापन कर सकता है। कंपाइलर आपके कोड के आधार पर और भी अधिक अनुकूलन कर सकता है। Arraymutating
मट्टियो पियोम्बो

38

में स्विफ्ट 3 और 4 , इस होगा:

नंबर के साथ, जॉनसन के जवाब के अनुसार:

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
   a.remove(at: i)
}
print(a)

ओपी के सवाल के रूप में तार के साथ :

var b = ["a", "b", "c", "d", "e", "f"]

for (i,str) in b.enumerated().reversed()
{
    if str == "c"
    {
        b.remove(at: i)
    }
}
print(b)

हालाँकि, अब स्विफ्ट 4.2 में या बाद में, वहाँ भी एक बेहतर, तेज़ तरीका है जिसे Apple द्वारा WWDC2018 में सुझाया गया था:

var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)

इस नए तरीके के कई फायदे हैं:

  1. यह कार्यान्वयन के मुकाबले तेज़ है filter
  2. यह सरणियों को उलटने की आवश्यकता से दूर होता है।
  3. यह आइटमों को इन-प्लेस से हटा देता है, और इस प्रकार यह नए एरे को आवंटित करने और वापस करने के बजाय मूल सरणी को अपडेट करता है।

क्या होगा अगर आइटम एक वस्तु है और मुझे इसकी जांच करने की आवश्यकता है, {$0 === Class.self}तो काम नहीं करता है
टॉमहॉवियर

14

जब एक निश्चित सूचकांक पर एक तत्व को एक सरणी से हटा दिया जाता है, तो बाद के सभी तत्वों में उनकी स्थिति (और सूचकांक) बदल जाएगी, क्योंकि वे एक स्थान पर वापस आ जाते हैं।

तो सबसे अच्छा तरीका है कि आप सरणी को रिवर्स ऑर्डर में नेविगेट करें - और इस मामले में मैं लूप के लिए एक पारंपरिक का उपयोग करने का सुझाव देता हूं:

for var index = array.count - 1; index >= 0; --index {
    if condition {
        array.removeAtIndex(index)
    }
}

हालांकि मेरे विचार में सबसे अच्छा तरीका filterविधि का उपयोग करके है , जैसा कि उनके उत्तर में @perlfly द्वारा वर्णित है।


लेकिन दुर्भाग्यपूर्ण रूप से इसे 3 में हटा दिया गया है
सर्गेई ब्रेजनिक

4

नहीं, यह ऐंठन के दौरान सरणियों को म्यूट करने के लिए सुरक्षित नहीं है, आपका कोड क्रैश हो जाएगा।

यदि आप केवल कुछ वस्तुओं को हटाना चाहते हैं, तो आप filterफ़ंक्शन का उपयोग कर सकते हैं ।


3
यह स्विफ्ट के लिए गलत है। Arrays मान प्रकार हैं, इसलिए उन्हें "कॉपी" किया जाता है, जब वे फ़ंक्शंस में पास हो जाते हैं, चर को सौंपा जाता है, या गणना में उपयोग किया जाता है। (स्विफ्ट, मूल्य प्रकार के लिए कॉपी-ऑन-राइट कार्यक्षमता को लागू करता है, इसलिए वास्तविक प्रतिलिपि न्यूनतम रखी जाती है।) सत्यापित करने के लिए निम्नलिखित प्रयास करें: var x = [1, 2, 3, 4, 5]; (x) मुद्रित; var i = 0; v में x के लिए {if (v% 2 == 0) {x.remove (at: i)} और {i + = 2}}; प्रिंट (x)
404compilernotfound

हाँ, आप सही हैं, बशर्ते कि आपको पता हो कि आप क्या कर रहे हैं। शायद मैंने अपनी प्रतिक्रिया स्पष्ट रूप से व्यक्त नहीं की। मुझे कहना चाहिए कि यह संभव है लेकिन यह सुरक्षित नहीं है । यह सुरक्षित नहीं है क्योंकि आप कंटेनर का आकार बदल रहे हैं और यदि आप अपने कोड में कोई गलती करते हैं, तो आपका ऐप क्रैश हो जाएगा। स्विफ्ट के सभी सुरक्षित कोड लिखने के बारे में है जो अप्रत्याशित रूप से रनटाइम पर क्रैश नहीं करेगा। यही कारण है कि functionnal प्रोग्रामिंग कार्यों जैसे का उपयोग कर filterरहा है सुरक्षित । यहाँ मेरा एक गूंगा उदाहरण है:var y = [1, 2, 3, 4, 5]; print(y); for (index, value) in y.enumerated() { y.remove(at: index) } print(y)
स्टार्सक्रीम

मैं सिर्फ यह भेद करना चाहता था कि स्विफ्ट में संग्रहित किए जा रहे संग्रह को संशोधित करना संभव है, ऐसा करने के अपवाद-फेंक व्यवहार के विपरीत जब एनएसएरे के माध्यम से तेजी से गणना या यहां तक ​​कि सी # संग्रह प्रकारों के माध्यम से पुनरावृत्ति होती है। यह संशोधन नहीं है जो यहां एक अपवाद को फेंक देगा, लेकिन इंडेक्स को कुप्रबंधित करने और सीमा से बाहर जाने की संभावना है (क्योंकि उन्होंने आकार में कमी की थी)। लेकिन मैं निश्चित रूप से आपके साथ सहमत हूं कि संग्रह में हेरफेर करने के लिए कार्यात्मक प्रोग्रामिंग प्रकार के तरीकों का उपयोग करना आमतौर पर सुरक्षित और स्पष्ट है। खासकर स्विफ्ट में।
404compilernotfound

2

या तो हटाए जाने वाले आइटमों को संग्रहीत करने के लिए एक परिवर्तनशील सरणी बनाएं और फिर गणना के बाद, उन वस्तुओं को मूल से हटा दें। या, सरणी की एक प्रति (अपरिवर्तनीय) बनाएँ, गणना करें और गणना करते समय मूल से वस्तुओं (सूचकांक द्वारा नहीं) को हटा दें।


2

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

var index = array.count-1
while index >= 0 {

     let element = array[index]
     //any operations on element
     array.remove(at: index)

     index -= 1
}

1

मैं एन्यूमरेशन के दौरान शून्य करने के लिए तत्वों को सेट करने की सलाह देता हूं, और सरणियों फिल्टर () पद्धति का उपयोग करके सभी खाली तत्वों को हटाने के बाद।


1
यह तभी काम करता है जब संग्रहित प्रकार एक वैकल्पिक है। यह भी ध्यान दें कि filterविधि नहीं निकालती है, यह एक नया सरणी बनाता है।
एंटोनियो

इस बात से सहमत। उलटा क्रम बेहतर समाधान है।
14

0

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

Like so, (one can copy and paste this on Playground)

var a = ["a", "b", "c", "d"]
var b = [1, 2, 3, 4]
var c = ["!", "@", "#", "$"]

// remove c, 3, #

for (index, ch) in a.enumerated().reversed() {
    print("CH: \(ch). INDEX: \(index) | b: \(b[index]) | c: \(c[index])")
    if ch == "c" {
        a.remove(at: index)
        b.remove(at: index)
        c.remove(at: index)
    }
}

print("-----")
print(a) // ["a", "b", "d"]
print(b) // [1, 2, 4]
print(c) // ["!", "@", "$"]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.