ฉันต้องการแจกแจงผ่านอาร์เรย์ใน Swift และลบบางรายการออก ฉันสงสัยว่าสิ่งนี้ปลอดภัยหรือไม่และถ้าไม่ฉันควรจะทำอย่างไร
ตอนนี้ฉันจะทำสิ่งนี้:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
ฉันต้องการแจกแจงผ่านอาร์เรย์ใน Swift และลบบางรายการออก ฉันสงสัยว่าสิ่งนี้ปลอดภัยหรือไม่และถ้าไม่ฉันควรจะทำอย่างไร
ตอนนี้ฉันจะทำสิ่งนี้:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
คำตอบ:
ใน Swift 2 ใช้งานง่ายมากenumerateและreverse.
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
a.removeAtIndex(i)
}
print(a)
filterส่งคืนอาร์เรย์ใหม่ คุณไม่ได้ลบอะไรออกจากอาร์เรย์ ฉันจะไม่เรียกfilterการแจงนับด้วยซ้ำ มีมากกว่าหนึ่งวิธีในการถลกหนังแมว
คุณอาจพิจารณาfilterวิธี:
var theStrings = ["foo", "bar", "zxy"]
// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }
พารามิเตอร์ของfilterเป็นเพียงปิดที่ใช้อินสแตนซ์ชนิดอาร์เรย์ (ในกรณีนี้String) Boolและผลตอบแทน เมื่อผลลัพธ์trueมันเก็บองค์ประกอบไว้มิฉะนั้นองค์ประกอบจะถูกกรองออก
filterไม่อัปเดตอาร์เรย์มันเพิ่งส่งคืนอันใหม่
filterวิธีการนี้กลายเป็นmutatingหนึ่งเดียว (เนื่องจากฉันได้อ่านmutatingคำหลักเปิดใช้งานฟังก์ชันเช่นนี้เพื่อแก้ไขselfแทน)
Arrayทำเครื่องหมายเป็นmutatingและคล้ายกับรหัสของคำถาม อย่างไรก็ตามโปรดพิจารณาว่านี่อาจไม่ใช่ข้อดีเสมอไป อย่างไรก็ตามทุกครั้งที่คุณลบวัตถุอาร์เรย์ของคุณอาจถูกจัดระเบียบใหม่ในหน่วยความจำ ดังนั้นจึงสามารถจัดสรรอาร์เรย์ใหม่ได้อย่างมีประสิทธิภาพมากขึ้นจากนั้นทำการแทนที่อะตอมด้วยผลลัพธ์ของฟังก์ชันตัวกรอง คอมไพเลอร์สามารถทำการเพิ่มประสิทธิภาพได้มากขึ้นโดยขึ้นอยู่กับโค้ดของคุณ
ในSwift 3 และ 4สิ่งนี้จะเป็น:
ด้วยตัวเลขตามคำตอบของ Johnston:
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
a.remove(at: i)
}
print(a)
โดยมีสตริงเป็นคำถามของ OP:
var b = ["a", "b", "c", "d", "e", "f"]
for (i,str) in b.enumerated().reversed()
{
if str == "c"
{
b.remove(at: i)
}
}
print(b)
อย่างไรก็ตามตอนนี้ใน Swift 4.2 หรือใหม่กว่ายังมีวิธีที่ดีกว่าและเร็วกว่าที่ Apple แนะนำใน WWDC2018:
var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)
วิธีใหม่นี้มีข้อดีหลายประการ:
filterมันจะเร็วกว่าการใช้งานด้วย{$0 === Class.self}ไม่ได้ผล
เมื่อองค์ประกอบที่ดัชนีบางรายการถูกลบออกจากอาร์เรย์องค์ประกอบที่ตามมาทั้งหมดจะมีการเปลี่ยนแปลงตำแหน่ง (และดัชนี) ของพวกเขาเนื่องจากพวกมันเลื่อนกลับไปทีละตำแหน่ง
ดังนั้นวิธีที่ดีที่สุดคือการนำทางอาร์เรย์ในลำดับย้อนกลับ - และในกรณีนี้ฉันขอแนะนำให้ใช้แบบดั้งเดิมสำหรับลูป:
for var index = array.count - 1; index >= 0; --index {
if condition {
array.removeAtIndex(index)
}
}
อย่างไรก็ตามในความคิดของฉันแนวทางที่ดีที่สุดคือการใช้filterวิธีการตามที่ @perlfly อธิบายไว้ในคำตอบของเขา
ไม่ปลอดภัยที่จะทำให้อาร์เรย์กลายพันธุ์ในระหว่างการแจงนับรหัสของคุณจะผิดพลาด
หากคุณต้องการลบวัตถุเพียงไม่กี่ชิ้นคุณสามารถใช้filterฟังก์ชันนี้ได้
filterเป็นที่ปลอดภัย นี่คือตัวอย่างโง่ ๆ ของฉัน:var y = [1, 2, 3, 4, 5]; print(y); for (index, value) in y.enumerated() { y.remove(at: index) } print(y)
สร้างอาร์เรย์ที่เปลี่ยนแปลงได้เพื่อจัดเก็บรายการที่จะลบจากนั้นหลังจากการแจงนับให้ลบรายการเหล่านั้นออกจากต้นฉบับ หรือสร้างสำเนาของอาร์เรย์ (ไม่เปลี่ยนรูป) แจกแจงและลบอ็อบเจ็กต์ (ไม่ใช่โดยดัชนี) ออกจากต้นฉบับในขณะที่แจกแจง
แบบดั้งเดิมสำหรับลูปสามารถแทนที่ได้ด้วย while loop แบบธรรมดาซึ่งมีประโยชน์หากคุณต้องดำเนินการอื่น ๆ ในแต่ละองค์ประกอบก่อนที่จะลบออก
var index = array.count-1
while index >= 0 {
let element = array[index]
//any operations on element
array.remove(at: index)
index -= 1
}
เพียงแค่เพิ่มหากคุณมีหลายอาร์เรย์และแต่ละองค์ประกอบในดัชนี N ของอาร์เรย์ A เกี่ยวข้องกับดัชนี N ของอาร์เรย์ B คุณก็ยังสามารถใช้วิธีการย้อนกลับอาร์เรย์ที่แจกแจงได้ (เช่นคำตอบที่ผ่านมา) แต่จำไว้ว่าเมื่อเข้าถึงและลบองค์ประกอบของอาร์เรย์อื่น ๆ ไม่จำเป็นต้องย้อนกลับ
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) // ["!", "@", "$"]