Swift: Finde ein Object im Array und lösche es

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Swift: Finde ein Object im Array und lösche es

    Hallo ihr lieben,

    ich arbeite gerade an einem Spiel und möchte ein ganz bestimmten Eintrag aus einem Array löschen. Gibt es eventuell die Möglichkeit, dies über eine Extension zu lösen?

    Ich speichere folgendes Struct in mein Array:


    Quellcode

    1. struct LastValidRoundItem {
    2. var player:Player
    3. var ergebnis:Int
    4. var id:Int
    5. }
    Nun möchte ich anhand der ID (im Struct-Obj LastValidRoundItem) das entsprechende Item LastValidRoundItem aus meinem Array löschen.

    Geht das? Ihr würdet mir mega weiterhelfen.

    Freue mich auf eure Antworten :)

    LG
    Florian
  • warum sollte das nicht gehen?
    wenn dir die performance egal ist, kannst du filter verwenden.
    ansonsten einfach das element suchen (schleife oder iterator) und entfernen.
    wenn es meherere objekte sein können dann musst du wohl einen reverse-enumerator verwenden oder eben eine herkömmliche schleife.
  • Flolle schrieb:

    ich … möchte ein ganz bestimmten Eintrag aus einem Array löschen. Gibt es eventuell die Möglichkeit, dies über eine Extension zu lösen?
    Mit index(where:) kann man den Index eines Elements in einem Array finden, das einem gegebenen Kriterium entspricht, und mit remove(at:) kann man das Element an diesem Index entfernen.

    Beide Funktionen kann man natürlich sehr leicht in einer Extension zusammenfassen:

    Quellcode

    1. extension Array {
    2. /// Removes the first element of the collection that satisfies the
    3. /// given predicate.
    4. /// Returns `true' if an element was removed or `false' if there
    5. /// was no element to remove.
    6. @discardableResult
    7. mutating func remove(where predicate: (Element) -> Bool) -> Bool {
    8. if let index = index(where: { predicate($0) }) {
    9. remove(at: index)
    10. return true
    11. }
    12. return false
    13. }
    14. }
    15. struct Foo {
    16. var id: Int
    17. init(_ id: Int) { self.id = id }
    18. }
    19. var foos = (1..<5).map{Foo($0)}
    20. print(foos) // [Foo(id: 1), Foo(id: 2), Foo(id: 3), Foo(id: 4)]
    21. foos.remove(where: { $0.id == 2 })
    22. print(foos) // [Foo(id: 1), Foo(id: 3), Foo(id: 4)]
    Alles anzeigen
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • Flolle schrieb:

    Hm, gibt es Extensions auch bei Obj-C.

    Wie schon beantwortet, ja.*

    Swift ist sozusagen ein bunt zusammengewürfelter Gemischtwarenladen. Es gibt eigentlich kein 'Swift-Feature', das es nicht auch in irgendeiner anderen Sprache gibt. Die Optionals vielleicht – auch nur beschränkt, zu einem gewissen Grad.

    Ob dieses Zusammengefringse von anderen Sprachen dann selbst wieder ein abgerundetes und stimmiges Gesamtbild ergibt, sei dahingestellt. Im Gegensatz zu mir verneint das die Mehrheit der aktiven Foristen hier.

    Ich finde es, mit Verlaub, wie @gritsch nur etwas merkwürdig, wenn Du Swift so über den grünen Klee lobst, gerade bei einem Fall, den Du selber nicht umsetzen konntest. Ist aber nicht so schlimm. Als Anfänger lernt man ja halt.^^


    *PS: In Objective-C gilt das freilich nur für Klassen und nicht für Wertetypen wie z.B. structs.
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • gritsch schrieb:

    macmoonshine schrieb:

    gritsch schrieb:

    Ja, nennt sich class category (was du suchst). es gibt aber auch extensions (das bedeutet aber bisschen was anderes).
    Eine Class-Extension in Objective-C ist letztendlich auch ein Kategorie. Deswegen heißen die ja auch anonyme Kategorien.
    Die hat aber keine eigene implementation.
    Eine Kategorie muss auch keine eigene Implementation haben. ;)
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    gritsch schrieb:

    macmoonshine schrieb:

    gritsch schrieb:

    Ja, nennt sich class category (was du suchst). es gibt aber auch extensions (das bedeutet aber bisschen was anderes).
    Eine Class-Extension in Objective-C ist letztendlich auch ein Kategorie. Deswegen heißen die ja auch anonyme Kategorien.
    Die hat aber keine eigene implementation.
    Eine Kategorie muss auch keine eigene Implementation haben. ;)
    muss nicht, kann aber (zb in dem fall hier dass du NSMutableArray erweitern würdest).
  • Um noch einmal auf die Swift-Seite der Extension-Medaille zurückzukommen…

    Ich finde es in Swift, ehrlich gesagt, teilweise etwas schwierig, herauszufinden, _wo_ man am besten mit einer Extension ansetzt.

    In einer 'reinen' OOP-Sprache ist das normalerweise klar. Möglichst weit oben in der (eindeutigen) Hierarchie an der Wurzelklasse.

    In meinem obigen Beispiel habe ich den konkreten (generischen) Wertetyp Array erweitert. Ein Array implementiert verschiedene Protokolle, die teilweise in einem hierarchischen Verhältnis zueinander stehen. Neben Array implementieren auch andere Typen diese Protokolle.

    Wenn man dann möglichst weit oben anfangen will, muß man sich in diesem Protokollgewust die richtigen Protokolle raussuchen. Teilweise schwierig, da durchzublicken. Ich finde nicht, daß Swift in diesem Punkt so intuitiv userfreundlich ist.

    In diesem konkreten Fall spielen zwei Funktionen eine Rolle: index(where:) und remove(at:). index(where:) findet sich im Protokoll Collection, mit dem man es neben Sequence noch eher häufiger zu tun bekommt. remove(at:) ist da aber nicht definiert. Wo zum Henker befindet sich remove(at:)!?

    Ich bin jetzt zufällig fündig geworden (deswegen schreibe ich das auch hier): In RangeReplaceableCollection! Ja, ne ist klar. Wo denn auch sonst?

    Obige Extension auf RangeReplaceableCollection angewandt sähe dann so aus:

    Quellcode

    1. extension RangeReplaceableCollection {
    2. @discardableResult
    3. mutating func remove(where predicate: (Self.Iterator.Element) -> Bool) -> Bool {
    4. if let index = index(where: { predicate($0) }) {
    5. remove(at: index)
    6. return true
    7. }
    8. return false
    9. }
    10. }
    11. struct Foo {
    12. var id: Int
    13. init(_ i: Int) { id = i }
    14. }
    15. var foos = (1..<4).map{ Foo($0) }
    16. print(foos) // [Foo(id: 1), Foo(id: 2), Foo(id: 3)]
    17. foos.remove(where: {$0.id == 2})
    18. print(foos) // [Foo(id: 1), Foo(id: 3)]
    Alles anzeigen
    Kein großer Unterschied, geht dann aber auch automatisch für ArraySlice, ContiguousArray, etc.
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • Das habe ich weiter oben im Code von Beitrag #3 als Inline-Kommentar klargestellt. Diesmal auf den Kommentar verzichtet.
    Dafür habe ich ja den Boolean-Rückgabewert eingebaut.

    Quellcode

    1. while foos.remove(where: {$0.id % 2 == 0}) {}
    entfernt alle Elemente mit dem Kriterium.
    Ansonsten würde ich eine Entferne-alle-Funktion wohl eher removeAll(where:) nennen. Die Tücken von API-Design…
    Mir ging's hier jetzt aber um etwas anderes.
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von torquato ()

  • Ich kann die Implementierung einer Kategorie

    torquato schrieb:

    Ansonsten würde ich eine Entferne-alle-Funktion wohl eher removeAll(where:) nennen. Die Tücken von API-Design…
    Oder du nennst remove(where:) in removeFirst(where:). Bei so allgemeinen Namen kommt man als Verwender sonst schnell ins Rätseln. Remove-Where würde ich auch eher als Remove-All-Where verstehen. ;)
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Oder du nennst remove(where:) in removeFirst(where:). Bei so allgemeinen Namen kommt man als Verwender sonst schnell ins Rätseln. Remove-Where würde ich auch eher als Remove-All-Where verstehen. ;)

    Joa… Das wäre wahrscheinlich besser. Ehrlich gesagt, um die Benennung habe ich mir da keine großen Gedanken gemacht, einfach nur irgendwie auf die Schnelle index(where:) und remove(at:) zusammengepackt. Darum soll sich der OP Gedanken machen, wie es ihm gefällt.

    macmoonshine schrieb:

    Ich kann die Implementierung einer Kategorie

    ??? ?(
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • macmoonshine schrieb:

    Anscheinend hat der Editor da etwas eingefügt, was ich vorher mal geschrieben aber nicht abgesendet habe.

    Das habe ich mir fast schon gedacht. Hätte ja aber auch sein können, daß etwas, was Du noch sagen wolltest, unabsichtlich verschluckt worden ist. Deshalb die Nachfrage.

    Aus Spaß an der Freude habe ich jetzt noch mal eine remove(where:)-Version geschrieben, die alle Elemente, die das Kriterium erfüllen, entfernt. Wie @gritsch schon oben angeregt hat, dann von hinten beginnend.

    Dabei tauchten zwei Schwierigkeiten auf.

    1.) Self.Indices.Iterator.Element ist nicht automatisch typgleich zu Self.Index. Für mich unverständlich. So sehr ich die Typsicherheit an Swift mag, aber manchmal verhält es sich da wie eine zickige Bitch.

    Besser man macht das als ein Constraint an die Extension, als daß man später mit as! Self.Index etc. unsicher rumoperieren muß.

    2.) Ich wollte das möglichst funktional formulieren. Jedoch, ein foreEach{ index in remove(at: index)} geht nicht. Wegen capture mutating self in closure oder so ähnlich. Weiß nicht, ob das nicht doch irgendwie geht.

    Wäre neugierig, ob jemandem was dazu einfällt.

    Hier anbei der Code von dem ich rede:

    Quellcode

    1. extension RangeReplaceableCollection where Indices.Iterator.Element == Index {
    2. mutating func remove(where predicate: (Iterator.Element) -> Bool) {
    3. let ixs = zip(indices, self).filter{(_, e) in predicate(e)}
    4. for (i, _) in ixs.reversed() {
    5. remove(at: i)
    6. }
    7. }
    8. }
    9. struct Foo {
    10. var id: Int
    11. init(_ x: Int){ id = x }
    12. }
    13. var foos = (1..<7).map{ Foo($0) }
    14. print(foos)
    15. // [Foo(id: 1), Foo(id: 2), Foo(id: 3), Foo(id: 4), Foo(id: 5), Foo(id: 6)]
    16. foos.remove(where: {$0.id % 2 == 0})
    17. print(foos)
    18. // [Foo(id: 1), Foo(id: 3), Foo(id: 5)]
    Alles anzeigen
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?