Swift3の配列からオブジェクトを削除する


93

私のアプリケーションでは、セルを選択するときに配列に1つのオブジェクトを追加し、セルを再選択するときにオブジェクトの選択を解除して削除しました。そのコードを使用しましたが、エラーが発生します。

extension Array {
    func indexOfObject(object : AnyObject) -> NSInteger {
        return (self as NSArray).indexOfObject(object)
    }

    mutating func removeObject(object : AnyObject) {
        for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) {
            self.removeAtIndex(index)
        }
    }
}

class MyViewController: UITableViewController {
    var arrContacts: [Any] = []
    var contacts: [Any] = []

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        arrContacts.removeObject(contacts[indexPath.row])
    }
}

それは私にそのような2つのエラーを与えます:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'

Set<Contact>配列ではなくを使用できます。連絡先オブジェクトに関する詳細情報を提供できますか?あなたはそれを自分で作っている場合は、それが準拠する必要がありますHashableEquatableセットでそれを置くために
Paulw11

回答:


166

NSMutableArray'sに相当するSwiftremoveObjectは次のとおりです。

var array = ["alpha", "beta", "gamma"]

if let index = array.firstIndex(of: "beta") {
    array.remove(at: index)
}

オブジェクトが一意の場合。キャストしNSArrayて使用する必要はまったくありませんindexOfObject:

APIindex(of:も機能しますが、これにより、に不要な暗黙のブリッジキャストが発生しNSArrayます。

同じオブジェクトが複数回出現する場合は、を使用しますfilter。ただし、データソース配列のように、インデックスが特定のオブジェクトに関連付けられている場合firstIndex(ofは、より高速であるため望ましいですfilter

更新:

スウィフトでは4.2 +あなたは、一つまたは複数の出現削除することができますbetaとしremoveAll(where:)

array.removeAll{$0 == "beta"}

34
これが最良の答えですが、remove(object: "beta")がないのは愚かなことではありません。
zeeple 2017年

5
.index(of: コレクションにEquatableタイプが含まれている場合にのみ利用できると思います。
Adam Waite 2017

@AdamWaiteはい。ただし、これはFoundationタイプにも当てはまります。
vadian 2017

これは正しくありません。複数の「ベータ版」がある場合はどうなりますか?これは、配列に複数のオカレンスが含まれていない場合にのみ機能します。正しい答えは、フィルタを使用するか、しばらくこの答えを実行しているwhile let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazallaその通りですが、配列に複数のオカレンスを含めることができる場合は、filterソリューションを使用してください。しかし、オブジェクトがユニークな場合はindex(of、それがよりもはるかにパフォーマンスが高いため、常に使用されますfilter
vadian 2018年

72
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }

7
これは、言語が提供する構文上の優れた機能を利用する正しいSwiftソリューションです。
マイケル

1
アイテムがオブジェクトの場合はどうなりますか?
TomSawyer

対象外フィルタに@TomSawyer、$ 0使用==!
マイクTaverneの

25

Swift 3の場合、index(where :)を使用して、配列内のオブジェクト($ 0)と探しているものとの比較を行うクロージャーを含めることができます。

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}

複数のオブジェクトを削除したい場合、これは機能しますか?like(where:{$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed

16

もう1つの便利で便利な解決策は、この種の拡張機能を作成することです。

extension Array where Element: Equatable {

    @discardableResult mutating func remove(object: Element) -> Bool {
        if let index = index(of: object) {
            self.remove(at: index)
            return true
        }
        return false
    }

    @discardableResult mutating func remove(where predicate: (Array.Iterator.Element) -> Bool) -> Bool {
        if let index = self.index(where: { (element) -> Bool in
            return predicate(element)
        }) {
            self.remove(at: index)
            return true
        }
        return false
    }

}

このように、カスタムオブジェクトを含む配列がある場合:

let obj1 = MyObject(id: 1)
let obj2 = MyObject(id: 2)
var array: [MyObject] = [obj1, obj2]

array.remove(where: { (obj) -> Bool in
    return obj.id == 1
})
// OR
array.remove(object: obj2) 

1
これは、配列に複数のオカレンスが含まれていない場合にのみ機能します。正しい答えは、フィルターを使用するか、この回答をしばらく実行することです。この拡張機能のユーザーとして、私はそれがすべての出現とだけでなく、1削除することを期待
juancazalla

それは素晴らしいremove(element: Element)ことですが、配列にはInt、Doubleなどの型も格納できるためです。これらはオブジェクトではありません。
Radek Wilczak 2018年

8

スウィフト5、これを使用Extension

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.firstIndex(of: element) {
            self.remove(at: i)
        }
    }
}

例:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")

スウィフト3、これを使用Extension

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.index(of: element) {
            self.remove(at: i)
        }
    }
}

例:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")

6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) Cスタイルのforループであり、削除されました

  2. コードを次のようなものに変更して、ループしている場合は同様のオブジェクトをすべて削除します。

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    

列挙->フィルター->マップおよびremove(at)はスマートなソリューションです。これをお勧めします
ライアンX

4

スウィフト4

var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]

if let index = students.firstIndex(where: { $0.hasPrefix("A") }) {
   students.remove(at: index)
}

3

Swift 3でこれらのオブジェクトの配列(「array」という名前)から一意のオブジェクト(「objectToRemove」という名前)を削除するための正しく機能する1行のソリューションは次のとおりです。

if let index = array.enumerated().filter( { $0.element === objectToRemove }).map({ $0.offset }).first {
   array.remove(at: index)
}

1

Swift3でこれを試してください

array.remove(at: Index)

の代わりに

array.removeAtIndex(index)

更新

"Declaration is only valid at file scope".

オブジェクトがスコープ内にあることを確認してください。スコープに「内部」を指定できます。これはデフォルトです。

index(of:<Object>) 動作するには、クラスはに準拠する必要があります Equatable


1

スウィフト3及び4

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

for (index, element) in array.enumerated().reversed() {
    array.remove(at: index)
}

Swift 4.2から、より高度なアプローチを使用できます(より高速でメモリ効率が良い)

array.removeAll(where: { $0 == "c" })

の代わりに

array = array.filter { !$0.hasPrefix("c") }

詳細はこちら


1

それを簡単に行い、Swift4.2以降のチェーンを可能にする配列の拡張:

public extension Array where Element: Equatable {
    @discardableResult
    public mutating func remove(_ item: Element) -> Array {
        if let index = firstIndex(where: { item == $0 }) {
            remove(at: index)
        }
        return self
    }

    @discardableResult
    public mutating func removeAll(_ item: Element) -> Array {
        removeAll(where: { item == $0 })
        return self
    }
}

使用可能な任意の過負荷を一致していない「(:)」引数ラベル
jeet.chanchawat

1
@ jeet.chanchawatは、おそらく別の迅速なバージョンです...ああ、この質問は3つでしたか?さて、私は後でそれを確認し、それは間違いなく私のために働いた、私が執筆の時点で4.2だったと思いますが、今覚えていない
Renetik

0

これは特定のオブジェクトのインデックスを見つけるための公式の回答であり、そのインデックスを使用して任意のオブジェクトを簡単に削除できます。

var students = ["Ben", "Ivy", "Jordell", "Maxime"]
if let i = students.firstIndex(of: "Maxime") {
     // students[i] = "Max"
     students.remove(at: i)
}
print(students)
// Prints ["Ben", "Ivy", "Jordell"]

リンクは次のとおりです:https//developer.apple.com/documentation/swift/array/2994720-firstindex


0

これは私が使用したものです(Swift 5)...

    extension Array where Element:Equatable
    {
        @discardableResult
        mutating func removeFirst(_ item:Any ) -> Any? {
            for index in 0..<self.count {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
            }
            return nil
        }
        @discardableResult
        mutating func removeLast(_ item:Any ) -> Any? {
            var index = self.count-1
            while index >= 0 {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
                index -= 1
            }
            return nil
        }
    }

    var arrContacts:[String] = ["A","B","D","C","B","D"]
    var contacts: [Any] = ["B","D"]
    print(arrContacts)
    var index = 1
    arrContacts.removeFirst(contacts[index])
    print(arrContacts)
    index = 0
    arrContacts.removeLast(contacts[index])
    print(arrContacts)

結果:

   ["A", "B", "D", "C", "B", "D"]
   ["A", "B", "C", "B", "D"]
   ["A", "B", "C", "D"]

重要:アイテムを削除する配列には、同等の要素(オブジェクト、文字列、数値など)が含まれている必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.