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)
ここで私のswiftstubを参照してください: http://swiftstub.com/944024718/?v=beta
filter
の方法を検討するかもしれません:
var theStrings = ["foo", "bar", "zxy"]
// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }
filter
のパラメーターは、配列型のインスタンス(この場合はString
)を取り、Bool
を返す単なるクロージャーです。結果がtrue
の場合、要素を保持します。それ以外の場合、要素は除外されます。
Swift 3および4では、これは次のようになります。
ジョンストンの答えによると、数字で:
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
a.remove(at: i)
}
print(a)
OPの質問としてstringsを使用:
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以降、さらに優れた、より高速な方法があります WWDC2018のApple:
var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)
この新しい方法にはいくつかの利点があります。
filter
を使用した実装よりも高速です。特定のインデックスの要素が配列から削除されると、後続のすべての要素の位置(およびインデックス)が変更されます。これは、それらが1つの位置だけシフトバックするためです。
したがって、最善の方法は、配列を逆順でナビゲートすることです。この場合、従来のforループを使用することをお勧めします。
for var index = array.count - 1; index >= 0; --index {
if condition {
array.removeAtIndex(index)
}
}
しかし、私の意見では、@ perlflyの回答で説明されているように、filter
メソッドを使用することが最善の方法です。
いいえ、列挙中に配列を変更するのは安全ではありません。コードがクラッシュします。
少数のオブジェクトのみを削除する場合は、filter
関数を使用できます。
削除可能なアイテムを格納する可変配列を作成し、列挙後にそれらのアイテムを元のアイテムから削除します。または、配列のコピー(不変)を作成し、それを列挙して、列挙中に元のオブジェクトから(インデックスではなく)オブジェクトを削除します。
列挙中に要素をnilに設定し、配列filter()メソッドを使用してすべての空の要素を削除することをお勧めします。