如何在Swift中从数组中删除一个元素

318

如何在苹果的新语言Swift中从数组中取消设置/删除元素?

以下是一些代码:

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

如何从数组中删除元素animals[2]

18个回答

413

let关键字用于声明不能被改变的常量。如果您想要修改一个变量,应该使用var,例如:

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

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

一个不改变原始集合的非变异替代方法是使用filter创建一个新的集合,其中不包含您想要删除的元素,例如:

一个保持原始集合不变的非变异替代方案是使用 filter 创建一个没有您想要移除元素的新集合,例如:

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

21
FYI:remove 返回已删除的元素:let animal = animals.remove(at: 2) - 2Toad
3
我们可以仅基于索引进行过滤吗? - shaqir saiyed
1
@shaqirsaiyed 你可以根据任何你能想到的谓词进行过滤。例如,你可以过滤掉所有以“s”结尾的动物。 - Womble
添加动物 = 宠物 - Puji Wahono
remove(at:) 在 Swift 5 中可以让我获取单个项目。 - Ahmadreza

287

鉴于

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"]

注意事项

  • 上述方法(除了filter)会就地修改数组并返回被移除的元素。
  • Swift指南:Map Filter Reduce
  • 如果你不想修改原始数组,可以使用dropFirstdropLast创建一个新数组。

更新到Swift 5.2


谢谢您提供这些示例。在您的“删除未知索引元素”>“用于多个元素”的示例中,如果我想要删除chimps && moose,您会写什么闭包呢?我正在寻找与{$0 != "chimps" && $0 != "moose"}不同的东西。 - user1585121
为什么要费力获取索引,只是为了将其传递呢? animals.removeAll{ $0 == "chimps" } - theZ3r0CooL

208
上面的答案似乎假设您知道要删除的元素的索引。 通常情况下,您知道要在数组中删除的对象的引用(例如,您已经遍历了数组并找到了它)。在这种情况下,直接使用对象引用可能会更容易,而无需在每个地方都传递其索引。因此,我建议使用此解决方案。它使用身份运算符 !==,用于测试两个对象引用是否都引用同一对象实例。
func delete(element: String) {
    list = list.filter { $0 != element }
}

当然,这不仅适用于String


32
应该是 list = list.filter({ $0 != element }) - Craig Grummitt
6
如果你想使用身份运算符进行检查,就不能这样做。 - Daniel
3
array.indexOf({ $0 == obj }) 可以翻译为 array.index(where: { $0 == obj }) - jrc
3
请注意,如果其他对象引用了“list”,那么使用此删除方法将不会更新其他数组引用,因为您正在将一个新的数组分配给“list”。这只是一个微妙的影响,如果您使用此方法从数组中删除元素。 - Crashalot
2
函数式编程范式依赖于不可变对象。也就是说,你不能改变它们。相反,你会创建一个新的对象。这就是 delete、map、reduce 等操作所做的事情。list 将成为一个新创建的对象。在上面的代码片段中,我将一个新创建的对象重新分配给了 list。这对我来说是有效的,因为我设计我的代码遵循函数式编程的方式。 - Daniel
显示剩余4条评论

68
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
有趣的是,这个数组中的元素都遵循了Equatable协议。 - Nicolas Manzini
1
太棒了。但如果你从协议列表开始,它就不起作用了,因为协议类型无法符合“可比较”(Equatable),只有具体类型才能符合协议 :-( - AW101
我喜欢这个解决方案,因为它涵盖了从结构体数组中删除元素的操作。 - Marcos
我正在寻找Objective-C中等价的remove函数。这个答案最适合这个问题。谢谢。 - Shihab

27

从Xcode 10+开始,并根据WWDC 2018 session 223,“Embracing Algorithms”,未来一个好的方法将是 mutating func removeAll(where predicate: (Element) throws -> Bool) rethrows

苹果公司的示例:

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."

请查看苹果公司的文档

所以在这个例子中,如果移除animals[2],也就是"chimps":

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

这种方法可能更可取,因为它具有良好的可扩展性(线性 vs 平方),易读且干净。请注意,它仅适用于Xcode 10+,并且在撰写本文时处于测试版。


removeAll(where:) 只能在 Swift 4.2 中使用。 - Vlad Pulichev
1
phrase.removeAll(where: vowels.contains) - Leo Dabus

25

对于Swift4:

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

1
这将删除每个匹配元素,而不仅仅是单个元素。假设有一个数组theArray = ["A", "B", "C", "A"],通过执行以下语句:let newArray = theArray.filter({$0 != "A"}),将生成新数组newArray == ["B", "C"]。 - Scooter

25

如果您拥有自定义对象的数组,您可以按特定属性进行搜索,如下所示:

if let index = doctorsInArea.firstIndex(where: {$0.id == doctor.id}){
    doctorsInArea.remove(at: index)
}

或者,如果您想通过姓名搜索,例如

if let index = doctorsInArea.firstIndex(where: {$0.name == doctor.name}){
    doctorsInArea.remove(at: index)
}

20

20

你可以这样做。首先确保Dog确实存在于数组中,然后将其删除。如果你认为Dog可能在你的数组中出现多次,请添加for语句。

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

for object in animals {
    if object == animalToRemove {
        animals.remove(at: animals.firstIndex(of: animalToRemove)!)
    }
}
如果你确信数组中只有一个 Dog,那么可以直接执行以下操作:
animals.remove(at: animals.firstIndex(of: 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.remove(at: array.firstIndex(of: numberToRemove)!)
        }
    }
    if object is String {
        // this will deal with strings
        if object == animalToRemove {
        array.remove(at: array.firstIndex(of: animalToRemove)!)
        }
    }
}

如果我的数组不包含字符串怎么办? - Apqu
@apqu 进行了另一个更新,' || object == Int()' 和 '|| object == String()' 是不必要的。 - GuiSoySauce
循环数组会降低效率。请尝试使用 .filter 和 .compactMap。 - MLBDG

16

在 Swift 中与数组相关的操作较少

创建数组

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

在数组中添加对象

stringArray = stringArray + ["Five"]

从索引对象中获取值

let x = stringArray[1]

追加对象

stringArray.append("At last position")

插入对象到索引

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

移除对象

stringArray.remove(at: 3)

连接对象值

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

stringArray += ["Five"] or even better is stringArray += CollectionOfOne("Five") - Leo Dabus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接