मान द्वारा ऑब्जेक्ट को निकालने के लिए ऐरे एक्सटेंशन


140
extension Array {
    func removeObject<T where T : Equatable>(object: T) {
        var index = find(self, object)
        self.removeAtIndex(index)
    }
}

हालाँकि, मुझे एक त्रुटि मिलती है var index = find(self, object)

'T' 'T' के लिए परिवर्तनीय नहीं है

मैंने इस विधि हस्ताक्षर के साथ भी प्रयास किया: func removeObject(object: AnyObject)हालाँकि, मुझे वही त्रुटि मिली:

'AnyObject' 'T' के लिए परिवर्तनीय नहीं है

ऐसा करने का उचित तरीका क्या है?


T whereअपनी विधि घोषणा से हटाने का प्रयास करें । तो बस func removeObject<T: Equatable>। यह प्रश्न संबंधित है: stackoverflow.com/questions/24091046/…
ahruss

जवाबों:


165

स्विफ्ट 2 के रूप में , यह एक प्रोटोकॉल एक्सटेंशन विधि के साथ प्राप्त किया जा सकता है । removeObject()सभी प्रकार के अनुरूप RangeReplaceableCollectionType(विशेष रूप से Array) यदि संग्रह के तत्व हैं, तो एक विधि के रूप में परिभाषित किया गया है Equatable:

extension RangeReplaceableCollectionType where Generator.Element : Equatable {

    // Remove first collection element that is equal to the given `object`:
    mutating func removeObject(object : Generator.Element) {
        if let index = self.indexOf(object) {
            self.removeAtIndex(index)
        }
    }
}

उदाहरण:

var ar = [1, 2, 3, 2]
ar.removeObject(2)
print(ar) // [1, 3, 2]

स्विफ्ट 2 / एक्सकोड 7 बीटा 2 के लिए अपडेट : जैसा कि एयरस्पिड वेग ने टिप्पणियों में देखा, अब वास्तव में जेनेरिक प्रकार पर एक विधि लिखना संभव है जो टेम्पलेट पर अधिक प्रतिबंधात्मक है, इसलिए विधि को अब वास्तव में विस्तार के रूप में परिभाषित किया जा सकता है। का Array:

extension Array where Element : Equatable {

    // ... same method as above ...
}

प्रोटोकॉल एक्सटेंशन में अभी भी बड़े प्रकार के सेट पर लागू होने का लाभ है।

स्विफ्ट 3 के लिए अपडेट :

extension Array where Element: Equatable {

    // Remove first collection element that is equal to the given `object`:
    mutating func remove(object: Element) {
        if let index = index(of: object) {
            remove(at: index)
        }
    }
}

1
बिल्कुल सही, आप स्विफ्ट (2) से प्यार करेंगे। मुझे वास्तव में पसंद है कि कैसे समय के साथ और चीजें संभव हो जाती हैं और सामान सरल हो जाता है
Kametrixom

1
अच्छा बिंदु, कई मायनों में यह तथ्य कि उत्तर अभी भी तकनीकी रूप से सही है, बस अब मुहावरेदार नहीं है, और भी बदतर है - लोग आएंगे, जवाब पढ़ेंगे, विचार करेंगे कि एक निशुल्क फ़ंक्शन इसे हल करने का सही तरीका है क्योंकि यह एक उच्च श्रेणी का उत्तर है। । बहुत बदसूरत परिदृश्य। मेटा पर पोस्ट करेंगे।
एयरस्पीड वेलोसिटी

1
@AirspeedVelocity: वाह, मुझे याद आया। क्या यह जारी नोटों में शामिल है?
मार्टिन आर।

1
यदि आप ओब्जेक जैसी ही कार्यक्षमता चाहते हैं (यानी केवल 1 के बजाय सभी मिलान वाली वस्तुओं को हटाते हैं), तो आप "यदि" से "जबकि" बदल सकते हैं
पावरटॉल्ड

2
स्विफ्ट 3 संस्करण महान है, लेकिन मैं थोड़ा अपने घोषणा का नाम बदलने होगा remove(object: Element)आदेश का अनुपालन करने में स्विफ्ट एपीआई डिज़ाइन दिशा निर्देशों और से बचने के शब्दाडंबर। मैंने इसे दर्शाते हुए एक संपादन प्रस्तुत किया है।
स्विफ्टकोड

66

आप जेनेरिक प्रकार पर एक विधि नहीं लिख सकते हैं जो टेम्पलेट पर अधिक प्रतिबंधात्मक है।

नोट : स्विफ्ट 2.0 के रूप में, अब आप उन तरीकों को लिख सकते हैं जो टेम्पलेट पर अधिक प्रतिबंधात्मक हैं । यदि आपने अपने कोड को 2.0 में अपग्रेड किया है, तो एक्सटेंशन का उपयोग करके इसे लागू करने के नए विकल्पों के लिए अन्य उत्तर नीचे देखें।

आपको त्रुटि मिलने का कारण यह 'T' is not convertible to 'T'है कि आप वास्तव में एक नया परिभाषित कर रहे हैं में अपनी पद्धति में T जो मूल T से संबंधित नहीं है। यदि आप अपनी विधि में T का उपयोग करना चाहते हैं, तो आप इसे अपनी विधि पर निर्दिष्ट किए बिना कर सकते हैं।

दूसरा त्रुटि प्राप्त करने का कारण यह 'AnyObject' is not convertible to 'T'है कि टी के लिए सभी संभावित मान सभी वर्ग नहीं हैं। किसी भी उदाहरण के लिए AnyObject में परिवर्तित होने के लिए, यह एक वर्ग होना चाहिए (यह एक संरचना, enum, आदि नहीं हो सकता है)।

आपका सबसे अच्छा शर्त यह है कि इसे एक ऐसा फंक्शन बनाया जाए जो एरे को एक तर्क के रूप में स्वीकार करे:

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}

या मूल सरणी को संशोधित करने के बजाय, आप अपनी विधि को कॉपी वापस करके अधिक थ्रेड को सुरक्षित और पुन: प्रयोज्य बना सकते हैं:

func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}

एक विकल्प के रूप में जिसकी मैं अनुशंसा नहीं करता हूं, आप अपने तरीके को चुपचाप विफल कर सकते हैं यदि सरणी में संग्रहीत प्रकार को विधि टेम्पलेट में परिवर्तित नहीं किया जा सकता है (जो समान है)। (स्पष्टता के लिए, मैं विधि के खाके के लिए T के बजाय U का उपयोग कर रहा हूं):

extension Array {
    mutating func removeObject<U: Equatable>(object: U) {
        var index: Int?
        for (idx, objectToCompare) in enumerate(self) {
            if let to = objectToCompare as? U {
                if object == to {
                    index = idx
                }
            }
        }

        if(index != nil) {
            self.removeAtIndex(index!)
        }
    }
}

var list = [1,2,3]
list.removeObject(2) // Successfully removes 2 because types matched
list.removeObject("3") // fails silently to remove anything because the types don't match
list // [1, 3]

संपादित करें मौन विफलता को दूर करने के लिए आप एक बूल के रूप में सफलता लौटा सकते हैं:

extension Array {
  mutating func removeObject<U: Equatable>(object: U) -> Bool {
    for (idx, objectToCompare) in self.enumerate() {  //in old swift use enumerate(self) 
      if let to = objectToCompare as? U {
        if object == to {
          self.removeAtIndex(idx)
          return true
        }
      }
    }
    return false
  }
}
var list = [1,2,3,2]
list.removeObject(2)
list
list.removeObject(2)
list

यहां अपना उत्तर देखें: stackoverflow.com/a/24939242/458960 मैं इसे इस तरह से करने में सक्षम क्यों हूं और findविधि का उपयोग नहीं कर रहा हूं ?
स्नोमैन

आपका तरीका रनटाइम क्रैश के लिए अतिसंवेदनशील है। मेरे कार्य के साथ, संकलक को ऐसा होने से रोका जाएगा।
आकर्षित

1
@Isuru यह विधि Equatableप्रोटोकॉल को लागू करने वाली किसी भी वस्तु के साथ काम करती है। UIView ऐसा करता है हां यह UIViews के साथ काम करेगा
drewag

4
वाह, एक तत्व को हटाने के लिए लूप के लिए लिखना, 90 के दशक तक यह है!
जोरायर

5
नवीनतम स्विफ्ट में। enumerate(self)ठीक करने के लिए हैself.enumerate()
TomSawyer

29

संक्षेप में और संक्षिप्त रूप से:

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) 
{
    var index = find(array, object)
    array.removeAtIndex(index!)
}

2
यह अच्छा है। बेशक, यह inoutभी बिना किया जा सकता है । inoutअक्षत के साथ भी , कोई भी उपयोग कर सकता है array = array.filter() { $0 != object }, मुझे लगता है।
डैन रोसेनस्टार्क

11
बल प्रयोग नहीं किया गया है, जो शून्य हो सकता है। "अगर इंड = इंडेक्स {array.removeAtIndex (इंडस्ट्रीज़)}" को
बदलें

17

उपरोक्त सभी पढ़ने के बाद, मेरे दिमाग में सबसे अच्छा जवाब है:

func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] {
  return fromArray.filter { return $0 != object }
}

नमूना:

var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = arrayRemovingObject("Cat", fromArray:myArray )

स्विफ्ट 2 (xcode 7b4) सरणी एक्सटेंशन:

extension Array where Element: Equatable {  
  func arrayRemovingObject(object: Element) -> [Element] {  
    return filter { $0 != object }  
  }  
}  

नमूना:

var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = myArray.arrayRemovingObject("Cat" )

स्विफ्ट 3.1 अपडेट

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

extension Array where Element:Equatable {
    public mutating func remove(_ item:Element ) {
        var index = 0
        while index < self.count {
            if self[index] == item {
                self.remove(at: index)
            } else {
                index += 1
            }
        }
    }

    public func array( removing item:Element ) -> [Element] {
        var result = self
        result.remove( item )
        return result
    }
}

नमूने:

// Mutation...
      var array1 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
      array1.remove("Cat")
      print(array1) //  ["Dog", "Turtle", "Socks"]

// Creation...
      let array2 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"]
      let array3 = array2.array(removing:"Cat")
      print(array3) // ["Dog", "Turtle", "Fish"]

क्या यह सरणी का एक नया उदाहरण नहीं लौटाता है?
19

हाँ। यह अधिक कार्यात्मक शैली है। YMMV।
दिसंबर

मैं इस मामले में कार्यात्मक स्टाइल को छोड़कर सहमत हूं, जब filterफ़ंक्शन पहले से ही आपके लिए उस कार्यक्षमता को संभालता है। यह डुप्लिकेट कार्यक्षमता लगता है। लेकिन फिर भी एक अच्छा जवाब:]
pxpgraphics 20:20

13

प्रोटोकॉल एक्सटेंशन के साथ आप ऐसा कर सकते हैं,

extension Array where Element: Equatable {
    mutating func remove(object: Element) {
        if let index = indexOf({ $0 == object }) {
            removeAtIndex(index)
        }
    }
}

कक्षाओं के लिए समान कार्यक्षमता,

स्विफ्ट 2

extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = indexOf({ $0 === object }) {
            removeAtIndex(index)
        }
    }
}

स्विफ्ट 3

extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = index(where: { $0 === object }) {
             remove(at: index)
        }
    }
}

लेकिन अगर एक वर्ग समान लागू करता है तो यह अस्पष्ट हो जाता है और संकलक एक त्रुटि देता है।


1
मुझे Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
जूता

6

स्विफ्ट 2.0 में प्रोटोकॉल एक्सटेंशन का उपयोग करने के साथ

extension _ArrayType where Generator.Element : Equatable{
    mutating func removeObject(object : Self.Generator.Element) {
        while let index = self.indexOf(object){
            self.removeAtIndex(index)
        }
    }
}

4

फ़िल्टरिंग का उपयोग करने के बारे में क्या? [AnyObject] के साथ भी निम्नलिखित काफी अच्छी तरह से काम करता है।

import Foundation
extension Array {
    mutating func removeObject<T where T : Equatable>(obj: T) {
        self = self.filter({$0 as? T != obj})
    }

}

2

संभावित असुरक्षित उपयोग के बिना किसी सरणी से आइटम को हटाने की एक और संभावना है, क्योंकि हटाने के लिए ऑब्जेक्ट का सामान्य प्रकार सरणी के प्रकार के समान नहीं हो सकता है। वैकल्पिक का उपयोग करना भी जाने का सही तरीका नहीं है क्योंकि वे बहुत धीमे हैं। इसलिए आप एक क्लोजर का उपयोग कर सकते हैं जैसे कि उदाहरण के लिए एक सरणी को सॉर्ट करते समय इसका उपयोग पहले से ही किया जाता है।

//removes the first item that is equal to the specified element
mutating func removeFirst(element: Element, equality: (Element, Element) -> Bool) -> Bool {
    for (index, item) in enumerate(self) {
        if equality(item, element) {
            self.removeAtIndex(index)
            return true
        }
    }
    return false
}

जब आप Arrayइस फ़ंक्शन के साथ वर्ग का विस्तार करते हैं, तो आप निम्न कार्य करके तत्वों को निकाल सकते हैं:

var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { $0 == $1 } //Banana is now removed

हालाँकि आप एक तत्व को केवल तभी हटा सकते हैं जब उसमें समान मेमोरी पता हो (केवल AnyObjectप्रोटोकॉल के अनुरूप कक्षाओं के लिए , निश्चित रूप से):

let date1 = NSDate()
let date2 = NSDate()
var array = [date1, date2]
array.removeFirst(NSDate()) { $0 === $1 } //won't do anything
array.removeFirst(date1) { $0 === $1 } //array now contains only 'date2'

अच्छी बात यह है, कि आप पैरामीटर की तुलना करने के लिए निर्दिष्ट कर सकते हैं। उदाहरण के लिए, जब आपके पास सरणियों की एक सरणी होती है, तो आप समानता को बंद करने के रूप में निर्दिष्ट कर सकते हैं { $0.count == $1.count }और पहले सरणी में समान आकार वाले को हटाने के लिए सरणी से हटा दिया जाता है।

आप फ़ंक्शन को फ़ंक्शन के रूप में भी छोटा कर सकते हैं mutating func removeFirst(equality: (Element) -> Bool) -> Bool, फिर उदाहरण के साथ equality(item)फ़ंक्शन का मूल्यांकन करें और कॉल करें array.removeFirst({ $0 == "Banana" })


चूंकि ==एक फ़ंक्शन है, आप इसे किसी भी प्रकार के लिए भी कह सकते हैं जो लागू होते हैं ==(जैसे स्ट्रिंग, इंट आदि):array.removeFirst("Banana", equality:==)
एविल सकल

@ स्विवल 2 स्विफ्ट 2 में यह नया है, मुझे लगता है - यदि आप चाहते हैं तो तदनुसार उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें
बोर्चेरो

2

विस्तार करने की आवश्यकता नहीं:

var ra = [7, 2, 5, 5, 4, 5, 3, 4, 2]

print(ra)                           // [7, 2, 5, 5, 4, 5, 3, 4, 2]

ra.removeAll(where: { $0 == 5 })

print(ra)                           // [7, 2, 4, 3, 4, 2]

if let i = ra.firstIndex(of: 4) {
    ra.remove(at: i)
}

print(ra)                           // [7, 2, 3, 4, 2]

if let j = ra.lastIndex(of: 2) {
    ra.remove(at: j)
}

print(ra)                           // [7, 2, 3, 4]

1

या के indexOfबजाय का उपयोग forकर enumerate:

extension Array where Element: Equatable {

   mutating func removeElement(element: Element) -> Element? {
      if let index = indexOf(element) {
         return removeAtIndex(index)
      }
      return nil
   }

   mutating func removeAllOccurrencesOfElement(element: Element) -> Int {
       var occurrences = 0
       while true {
          if let index = indexOf(element) {
             removeAtIndex(index)
             occurrences++
          } else {
             return occurrences
          }
       }
   }   
}

1

शायद मुझे सवाल समझ में नहीं आया।

यह काम क्यों नहीं करेगा?

import Foundation
extension Array where Element: Equatable {
    mutating func removeObject(object: Element) {
        if let index = self.firstIndex(of: object) {
            self.remove(at: index)
        }
    }
}

var testArray = [1,2,3,4,5,6,7,8,9,0]
testArray.removeObject(object: 6)
let newArray = testArray

var testArray2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
testArray2.removeObject(object: "6")
let newArray2 = testArray2

0

मैं अंत में निम्नलिखित कोड के साथ समाप्त हुआ।

extension Array where Element: Equatable {

    mutating func remove<Element: Equatable>(item: Element) -> Array {
        self = self.filter { $0 as? Element != item }
        return self
    }

}

0

मैं एक को दूर करने में कामयाब रहे [String:AnyObject]एक सरणी से [[String:AnyObject]]पाश के लिए एक की गिनती के बाहर लागू करने के बाद से सूचकांक का प्रतिनिधित्व करने के द्वारा .findऔर .filterसाथ संगत नहीं हैं [String:AnyObject]

let additionValue = productHarvestChoices[trueIndex]["name"] as! String
var count = 0
for productHarvestChoice in productHarvestChoices {
  if productHarvestChoice["name"] as! String == additionValue {
    productHarvestChoices.removeAtIndex(count)
  }
  count = count + 1
}

-1

स्विफ्ट 2 में कार्यान्वयन:

extension Array {
  mutating func removeObject<T: Equatable>(object: T) -> Bool {
    var index: Int?
    for (idx, objectToCompare) in self.enumerate() {
      if let toCompare = objectToCompare as? T {
        if toCompare == object {
          index = idx
          break
        }
      }
    }
    if(index != nil) {
      self.removeAtIndex(index!)
      return true
    } else {
      return false
    }
  }
}

-4

मैं इसके साथ काम करने में सक्षम था:

extension Array {
    mutating func removeObject<T: Equatable>(object: T) {
        var index: Int?
        for (idx, objectToCompare) in enumerate(self) {
            let to = objectToCompare as T
            if object == to {
                index = idx
            }
        }

        if(index) {
            self.removeAtIndex(index!)
        }
    }
}

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