วิธีการลบองค์ประกอบออกจากอาร์เรย์ใน Swift


236

ฉันจะยกเลิกการตั้งค่า / ลบองค์ประกอบออกจากอาร์เรย์ใน Swift ภาษาใหม่ของ Apple ได้อย่างไร

นี่คือรหัสบางส่วน:

let animals = ["cats", "dogs", "chimps", "moose"]

องค์ประกอบanimals[2]จะถูกลบออกจากอาร์เรย์ได้อย่างไร

คำตอบ:


300

letคำหลักเป็นค่าคงที่ประกาศว่าไม่สามารถเปลี่ยนแปลงได้ หากคุณต้องการแก้ไขตัวแปรคุณควรใช้varแทนเช่น:

var animals = ["cats", "dogs", "chimps", "moose"]

animals.remove(at: 2)  //["cats", "dogs", "moose"]

ทางเลือกที่ไม่มีการกลายพันธุ์ที่จะทำให้คอลเลกชันดั้งเดิมไม่เปลี่ยนแปลงคือการใช้filterเพื่อสร้างคอลเลกชันใหม่โดยไม่ต้องลบองค์ประกอบที่คุณต้องการเช่น:

let pets = animals.filter { $0 != "chimps" }

7
FYI: removeส่งคืนองค์ประกอบที่ถูกลบ:let animal = animals.remove(at: 2)
โหลด

1
เราสามารถกรองตามดัชนีได้หรือไม่?
shaqir saiyed

@ Shaqirsaiyed คุณสามารถกรองคำกริยาใด ๆ ที่คุณคิดได้ เช่นคุณสามารถกรองสัตว์ทั้งหมดที่ลงท้ายด้วย "s"
Womble

เพิ่มสัตว์ = สัตว์เลี้ยง
Puji Wahono

197

ป.ร. ให้ไว้

var animals = ["cats", "dogs", "chimps", "moose"]

ลบองค์ประกอบแรก

animals.removeFirst() // "cats"
print(animals)        // ["dogs", "chimps", "moose"]

ลบองค์ประกอบสุดท้าย

animals.removeLast() // "moose"
print(animals)       // ["cats", "dogs", "chimps"]

ลบองค์ประกอบที่ดัชนี

animals.remove(at: 2) // "chimps"
print(animals)           // ["cats", "dogs", "moose"]

ลบองค์ประกอบของดัชนีที่ไม่รู้จัก

สำหรับองค์ประกอบเดียวเท่านั้น

if let index = animals.firstIndex(of: "chimps") {
    animals.remove(at: index)
}
print(animals) // ["cats", "dogs", "moose"]

สำหรับองค์ประกอบหลายรายการ

var animals = ["cats", "dogs", "chimps", "moose", "chimps"]

animals = animals.filter(){$0 != "chimps"}
print(animals) // ["cats", "dogs", "moose"]

หมายเหตุ

อัปเดตเป็น Swift 5.2


ขอบคุณสำหรับตัวอย่างเหล่านี้ในตัวคุณลบองค์ประกอบของดัชนีที่ไม่รู้จัก > สำหรับองค์ประกอบหลายรายการคุณจะเขียนการปิดเพื่อลบchimps && mooseตัวอย่างเช่น? ฉันกำลังมองหาบางอย่างที่แตกต่างกว่า{$0 != "chimps" && $0 != "moose"}

161

คำตอบข้างต้นดูเหมือนจะเข้าใจว่าคุณรู้ว่าดัชนีขององค์ประกอบที่คุณต้องการลบ

บ่อยครั้งที่คุณรู้จักการอ้างอิงไปยังวัตถุที่คุณต้องการลบในอาร์เรย์ (คุณวนซ้ำผ่านอาร์เรย์ของคุณและพบมันเช่น) ในกรณีเช่นนี้มันอาจจะทำงานได้ง่ายขึ้นกับการอ้างอิงวัตถุโดยตรงโดยไม่ต้องผ่านทุกดัชนีของมัน ดังนั้นฉันขอแนะนำวิธีนี้ มันใช้ตัวดำเนินการประจำตัว !==ซึ่งคุณใช้เพื่อทดสอบว่าวัตถุสองอ้างอิงทั้งสองอ้างถึงอินสแตนซ์วัตถุเดียวกัน

func delete(element: String) {
    list = list.filter() { $0 !== element }
}

แน่นอนว่านี่ไม่ได้ผลสำหรับStrings เท่านั้น


23
ควรเป็นlist = list.filter({ $0 != element })
Craig Grummitt

5
ไม่ใช่ถ้าคุณต้องการตรวจสอบกับผู้ดำเนินการประจำตัว
Daniel

3
array.indexOf({ $0 == obj })
jrc

2
หมายเหตุถ้าวัตถุอื่น ๆ ที่อ้างอิงlistการลบนี้จะไม่อัปเดตการอ้างอิงอาร์เรย์อื่น ๆ listตั้งแต่คุณกำหนดอาร์เรย์ใหม่เพื่อ เพียงแค่ความหมายที่ลึกซึ้งถ้าคุณลบจากอาร์เรย์ด้วยวิธีนี้
Crashalot

1
กระบวนทัศน์การตั้งโปรแกรมการทำงานอาศัยวัตถุที่ไม่เปลี่ยนรูป เช่นคุณไม่เปลี่ยน คุณสร้างวัตถุใหม่แทน นี่คือสิ่งที่ลบแผนที่ลดและอื่น ๆ รายการจะเป็นวัตถุที่สร้างขึ้นใหม่ ในตัวอย่างโค้ดข้างต้นฉันกำหนดกลับไปยังรายการวัตถุที่สร้างขึ้นใหม่ มันเหมาะกับฉันเพราะฉันออกแบบรหัสของฉันในลักษณะที่เป็นไปตามการเขียนโปรแกรมการทำงาน
Daniel

44

Swift 5: นี่คือส่วนขยายที่เย็นและง่ายต่อการลบองค์ประกอบในอาร์เรย์โดยไม่ต้องกรอง:

   extension Array where Element: Equatable {

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

}

การใช้งาน:

var myArray = ["cat", "barbecue", "pancake", "frog"]
let objectToRemove = "cat"

myArray.remove(object: objectToRemove) // ["barbecue", "pancake", "frog"]

ใช้งานได้กับประเภทอื่น ๆ เช่นIntเนื่องจากElementเป็นประเภททั่วไป:

var myArray = [4, 8, 17, 6, 2]
let objectToRemove = 17

myArray.remove(object: objectToRemove) // [4, 8, 6, 2]

1
น่าสนใจแถวนี้ที่องค์ประกอบ: ส่วนที่เท่าเทียม
นิโคลัส Manzini

1
สุกใส แม้ว่ามันจะไม่ทำงานหากคุณเริ่มต้นด้วยรายการโปรโตคอลเนื่องจาก - ประเภทโปรโตคอลไม่สอดคล้องกับ 'Equatable' เพราะมีเพียงรูปแบบคอนกรีตเท่านั้นที่สามารถปฏิบัติตามโปรโตคอล :-(
AW101

22

สำหรับ Swift4:

list = list.filter{$0 != "your Value"}

15

ตั้งแต่ Xcode 10+ และตามเซสชัน WWDC 2018 223 "การไพบูลย์อัลกอริธึม" จะเป็นวิธีการที่ดีในอนาคตmutating func removeAll(where predicate: (Element) throws -> Bool) rethrows

ตัวอย่างของ Apple:

var phrase = "The rain in Spain stays mainly in the plain."
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]

phrase.removeAll(where: { vowels.contains($0) })
// phrase == "Th rn n Spn stys mnly n th pln."

ดู เอกสารประกอบของ Apple

ดังนั้นในตัวอย่างของ OP การลบสัตว์ [2], "chimps":

var animals = ["cats", "dogs", "chimps", "moose"]
animals.removeAll(where: { $0 == "chimps" } )
// or animals.removeAll { $0 == "chimps" }

วิธีนี้อาจเป็นที่ต้องการเนื่องจากมีการปรับขนาดได้ดี (linear vs quadratic) สามารถอ่านได้และสะอาด โปรดทราบว่าใช้งานได้เฉพาะใน Xcode 10+ เท่านั้นและในขณะที่เขียนสิ่งนี้อยู่ในรุ่นเบต้า


removeAll (โดยที่ :) จะสามารถทำได้ใน swift 4.2 เท่านั้น
Vlad Pulichev

14

การดำเนินการบางอย่างเกี่ยวข้องกับ Array in Swift

สร้างอาร์เรย์

var stringArray = ["One", "Two", "Three", "Four"]

เพิ่มวัตถุในอาร์เรย์

stringArray = stringArray + ["Five"]

รับค่าจากวัตถุดัชนี

let x = stringArray[1]

ผนวกวัตถุ

stringArray.append("At last position")

แทรกวัตถุที่ดัชนี

stringArray.insert("Going", atIndex: 1)

ลบวัตถุ

stringArray.removeAtIndex(3)

ค่าวัตถุ Concat

var string = "Concate Two object of Array \(stringArray[1]) + \(stringArray[2])"

14

คุณสามารถทำได้ ก่อนอื่นตรวจสอบให้แน่ใจว่าDogมีอยู่จริงในอาร์เรย์แล้วลบออก เพิ่มforคำสั่งถ้าคุณเชื่อว่าDogอาจเกิดขึ้นมากกว่าหนึ่งครั้งในอาร์เรย์ของคุณ

var animals = ["Dog", "Cat", "Mouse", "Dog"]
let animalToRemove = "Dog"

for object in animals
{
    if object == animalToRemove{
        animals.removeAtIndex(animals.indexOf(animalToRemove)!)
    }
}

หากคุณแน่ใจว่าDogออกจากอาร์เรย์แล้วเกิดขึ้นเพียงครั้งเดียว:

animals.removeAtIndex(animals.indexOf(animalToRemove)!)

หากคุณมีทั้งสตริงและตัวเลข

var array = [12, 23, "Dog", 78, 23]
let numberToRemove = 23
let animalToRemove = "Dog"

for object in array
{

    if object is Int
    {
        // this will deal with integer. You can change to Float, Bool, etc...
        if object == numberToRemove
        {
        array.removeAtIndex(array.indexOf(numberToRemove)!)
        }
    }
    if object is String
    {
        // this will deal with strings
        if object == animalToRemove
        {
        array.removeAtIndex(array.indexOf(animalToRemove)!)
        }
    }
}

เกิดอะไรขึ้นถ้าอาร์เรย์ของฉันไม่มีสตริง?
Apqu

@apqu ทำการอัปเดตอีกครั้ง '|| วัตถุ == Int () 'และ' || วัตถุ == String () 'ไม่จำเป็น
GuiSoySauce

วนลูปอาร์เรย์ไปอย่างมีประสิทธิภาพ ตรวจสอบ. ฟิลเตอร์, compactMap
MLBDG

11

หากคุณไม่รู้จักดัชนีขององค์ประกอบที่คุณต้องการลบและองค์ประกอบนั้นสอดคล้องกับโปรโตคอล Equatable คุณสามารถทำได้:

animals.removeAtIndex(animals.indexOf("dogs")!)

ดูคำตอบโปรโตคอลที่เท่าเทียมกัน: ฉันจะทำ indexOfObject หรือมีOffjectที่เหมาะสมได้อย่างไร


10

ลบองค์ประกอบโดยใช้อาร์เรย์ดัชนี:

  1. Array of Strings และดรรชนี

    let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
    let indexAnimals = [0, 3, 4]
    let arrayRemainingAnimals = animals
        .enumerated()
        .filter { !indexAnimals.contains($0.offset) }
        .map { $0.element }
    
    print(arrayRemainingAnimals)
    
    //result - ["dogs", "chimps", "cow"]
  2. อาร์เรย์ของจำนวนเต็มและดัชนี

    var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    let indexesToRemove = [3, 5, 8, 12]
    
    numbers = numbers
        .enumerated()
        .filter { !indexesToRemove.contains($0.offset) }
        .map { $0.element }
    
    print(numbers)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]



ลบองค์ประกอบโดยใช้ค่าองค์ประกอบของอาร์เรย์อื่น

  1. อาร์เรย์ของจำนวนเต็ม

    let arrayResult = numbers.filter { element in
        return !indexesToRemove.contains(element)
    }
    print(arrayResult)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
  2. อาร์เรย์ของสตริง

    let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
    let arrayRemoveLetters = ["a", "e", "g", "h"]
    let arrayRemainingLetters = arrayLetters.filter {
        !arrayRemoveLetters.contains($0)
    }
    
    print(arrayRemainingLetters)
    
    //result - ["b", "c", "d", "f", "i"]

4
นี่คือหนึ่งคำตอบของสายการบินและมีประสิทธิภาพมากสำหรับการเข้ารหัสที่ดีขึ้นและการดำเนินการที่รวดเร็ว
iOSDev

สวัสดี @Krunal - คำตอบที่ดีคุณช่วยลองดูคำถามต่อไปนี้ (ปล่อยรูปภาพจากอาร์เรย์ภาพ): stackoverflow.com/questions/47735975//
โปรแกรมเมอร์เซิร์ฟเวอร์

6

เกี่ยวกับทางเลือกของ @ Suragch ในการ "ลบองค์ประกอบของดัชนีที่ไม่รู้จัก":

มี "indexOf (องค์ประกอบ)" รุ่นที่มีประสิทธิภาพมากกว่าที่จะจับคู่กับเพรดิเคตแทนที่จะเป็นวัตถุ มันใช้ชื่อเดียวกัน แต่ถูกเรียกโดย myObjects.indexOf {$ 0.property = valueToMatch} มันจะส่งคืนดัชนีของรายการแรกที่พบในอาร์เรย์ myObjects

หากองค์ประกอบนั้นเป็นวัตถุ / โครงสร้างคุณอาจต้องการลบองค์ประกอบนั้นตามมูลค่าของคุณสมบัติอย่างใดอย่างหนึ่ง เช่นคุณมีคลาสรถยนต์ที่มีคุณสมบัติ car.color และคุณต้องการลบรถ "สีแดง" ออกจากรถของคุณอาเรย์

if let validIndex = (carsArray.indexOf{$0.color == UIColor.redColor()}) {
  carsArray.removeAtIndex(validIndex)
}

ก่อนหน้านี้คุณสามารถทำสิ่งนี้ใหม่เพื่อลบรถสีแดง "ทั้งหมด" โดยการฝังคำสั่งด้านบนหากมีการวนซ้ำในขณะที่วนซ้ำและแนบบล็อกอื่นเพื่อตั้งค่าสถานะเป็น "แยก" ออกจากวง



4

หากคุณมีอาร์เรย์ของวัตถุที่กำหนดเองคุณสามารถค้นหาตามคุณสมบัติเฉพาะเช่นนี้:

    if let index = doctorsInArea.indexOf({$0.id == doctor.id}){
        doctorsInArea.removeAtIndex(index)
    }

หรือถ้าคุณต้องการค้นหาตามชื่อ

    if let index = doctorsInArea.indexOf({$0.name == doctor.name}){
        doctorsInArea.removeAtIndex(index)
    }

3

สิ่งนี้ควรทำ (ไม่ได้ทดสอบ):

animals[2..3] = []

แก้ไข: และคุณต้องทำให้เป็นvarไม่ใช่ไม่ใช่letหรือเป็นค่าคงที่ไม่เปลี่ยนรูป


5
เมื่อใช้ช่วง (ย่อย) ของอาร์เรย์ที่มีอยู่เพื่อสร้างอาร์เรย์อื่นช่วงนั้นจะต้องมี 3 จุด ข้างต้นควรเขียนเป็นสัตว์ [2 ... 3]
zevij

3

ฉันมาพร้อมกับส่วนขยายต่อไปนี้ที่ดูแลการลบองค์ประกอบออกจากArrayสมมติว่าองค์ประกอบในการArrayใช้งานEquatable:

extension Array where Element: Equatable {

  mutating func removeEqualItems(item: Element) {
    self = self.filter { (currentItem: Element) -> Bool in
      return currentItem != item
    }
  }

  mutating func removeFirstEqualItem(item: Element) {
    guard var currentItem = self.first else { return }
    var index = 0
    while currentItem != item {
      index += 1
      currentItem = self[index]
    }
    self.removeAtIndex(index)
  }

}

การใช้งาน:

var test1 = [1, 2, 1, 2]
test1.removeEqualItems(2) // [1, 1]

var test2 = [1, 2, 1, 2]
test2.removeFirstEqualItem(2) // [1, 1, 2]

สวัสดี @nburk - คำตอบที่ดีคุณช่วยลองดูคำถามต่อไปนี้ (ปล่อยรูปภาพจากอาร์เรย์ภาพ): stackoverflow.com/questions/47735975//
โปรแกรมเมอร์เซิร์ฟเวอร์

1

ส่วนขยายเพื่อลบวัตถุสตริง

extension Array {
    mutating func delete(element: String) {
        self = self.filter() { $0 as! String != element }
    }
}

การบังคับเปิดเครื่องอาจทำให้เกิดความผิดพลาดได้ฉันคิดว่าคุณควรหลีกเลี่ยงในกรณีนี้
user3206558

func "กลายพันธุ์" คืออะไร?
AwesomeElephant8232

มันเคยบอกว่าฟังก์ชั่นนี้จะเปลี่ยนตัวเอง (อาร์เรย์)
Varun Naharia

1

ฉันใช้ส่วนขยายนี้เกือบเหมือนกับ Varun แต่อันนี้ (ด้านล่าง) เป็นจุดประสงค์ทั้งหมด:

 extension Array where Element: Equatable  {
        mutating func delete(element: Iterator.Element) {
                self = self.filter{$0 != element }
        }
    }

1

ในการลบองค์ประกอบจากอาร์เรย์ใช้remove(at:), และremoveLast()removeAll()

yourArray = [1,2,3,4]

ลบค่าที่ 2 ตำแหน่ง

yourArray.remove(at: 2)

ลบค่าสุดท้ายออกจากอาร์เรย์

yourArray.removeLast()

ลบสมาชิกทั้งหมดออกจากชุด

yourArray.removeAll()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.