Überprüfen Sie, ob das optionale Array leer ist

74

In Objective-C, wenn ich ein Array habe

NSArray *array;

und ich möchte überprüfen, ob es nicht leer ist, ich mache immer:

if (array.count > 0) {
    NSLog(@"There are objects!");
} else {
    NSLog(@"There are no objects...");
}

Auf diese Weise muss nicht überprüft werden, ob array == nilder Code in dieser Situation in den elseFall fällt, und ein nicht nilleeres Array würde dies tun.

In Swift bin ich jedoch auf die Situation gestoßen, in der ich ein optionales Array habe:

var array: [Int]?

und ich bin nicht in der Lage herauszufinden, welche Bedingung zu verwenden ist. Ich habe einige Optionen, wie:

Option A: Überprüfen Sie sowohl nicht nilals auch leere Fälle im selben Zustand:

if array != nil && array!.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

Option B: Lösen Sie die Bindung des Arrays mit let:

if let unbindArray = array {
    if (unbindArray.count > 0) {
        println("There are objects!")
    } else {
        println("There are no objects...")
    }
} else {
    println("There are no objects...")
}

Option C: Verwenden des von Swift bereitgestellten Koaleszenzoperators:

if (array?.count ?? 0) > 0 {
    println("There are objects")
} else {
    println("No objects")
}

Ich mag die Option B nicht sehr, weil ich Code unter zwei Bedingungen wiederhole. Ich bin mir jedoch nicht sicher, ob die Optionen A und C korrekt sind oder ob ich eine andere Methode verwenden sollte.

Ich weiß, dass die Verwendung eines optionalen Arrays je nach Situation vermieden werden kann, aber in einigen Fällen kann es erforderlich sein, zu fragen, ob es leer ist. Ich würde gerne wissen, wie es am einfachsten geht.


BEARBEITEN:

Wie @vacawama betonte, funktioniert diese einfache Art der Überprüfung:

if array?.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

Ich habe jedoch den Fall ausprobiert, in dem ich etwas Besonderes nur dann tun möchte, wenn es nilleer oder leer ist, und dann fortfahren möchte, unabhängig davon, ob das Array Elemente enthält oder nicht. Also habe ich versucht:

if array?.count == 0 {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

Und auch

if array?.isEmpty == true {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

Aber wenn Array ist nil, fällt es nicht in den ifKörper. Und das liegt daran, dass in diesem Fall array?.count == nilund array?.isEmpty == nilso die Ausdrücke array?.count == 0und array?.isEmpty == truebeide ausgewertet werden false.

Ich versuche also herauszufinden, ob es eine Möglichkeit gibt, dies auch mit nur einer Bedingung zu erreichen.

eze.scaruli
quelle
Gibt es einen Grund, warum Sie das Array optional gemacht haben? Für Tabellenansichten und andere Dinge verwende ich nicht optional, da (wie Sie sagten) nil dasselbe ist wie keine Objekte. Wenn Sie also nil entfernen, reduzieren Sie die Komplexität, ohne die Funktionalität zu verlieren.
Fogmeister
Ich denke, diese Option Aist am besten lesbar. Das ist das Einzige, worauf Sie achten sollten.
Sulthan

Antworten:

138

Aktualisierte Antwort für Swift 3 und höher:

Swift 3 hat die Möglichkeit zum Vergleichen von Optionen mit >und entfernt <, sodass einige Teile der vorherigen Antwort nicht mehr gültig sind.

Es ist weiterhin möglich, Optionen mit zu vergleichen. ==Der einfachste Weg, um zu überprüfen, ob ein optionales Array Werte enthält, ist:

if array?.isEmpty == false {
    print("There are objects!")
}

Andere Möglichkeiten:

if array?.count ?? 0 > 0 {
    print("There are objects!")
}

if !(array?.isEmpty ?? true) {
    print("There are objects!")
}

if array != nil && !array!.isEmpty {
    print("There are objects!")
}

if array != nil && array!.count > 0 {
    print("There are objects!")
}

if !(array ?? []).isEmpty {
    print("There are objects!")
}

if (array ?? []).count > 0 {
    print("There are objects!")
}

if let array = array, array.count > 0 {
    print("There are objects!")
}

if let array = array, !array.isEmpty {
    print("There are objects!")
}

Wenn Sie etwas tun möchten, wenn das Array nilleer ist oder ist, haben Sie mindestens 6 Möglichkeiten:

Option A:

if !(array?.isEmpty == false) {
    print("There are no objects")
}

Option B:

if array == nil || array!.count == 0 {
    print("There are no objects")
}

Option C:

if array == nil || array!.isEmpty {
    print("There are no objects")
}

Option D:

if (array ?? []).isEmpty {
    print("There are no objects")
}

Option E:

if array?.isEmpty ?? true {
    print("There are no objects")
}

Option F:

if (array?.count ?? 0) == 0 {
    print("There are no objects")
}

Option C erfasst genau, wie Sie es auf Englisch beschrieben haben: "Ich möchte etwas Besonderes nur tun, wenn es null oder leer ist." Ich würde empfehlen, dass Sie dies verwenden, da es leicht zu verstehen ist. Daran ist nichts auszusetzen, zumal es "kurzschließt" und die Prüfung auf leer überspringt, wenn die Variable ist nil.



Vorherige Antwort für Swift 2.x:

Sie können einfach tun:

if array?.count > 0 {
    print("There are objects")
} else {
    print("No objects")
}

Wie @Martin in den Kommentaren hervorhebt, func ><T : _Comparable>(lhs: T?, rhs: T?) -> Boolbedeutet dies, dass der Compiler 0als Wraps umschließt, Int?damit der Vergleich mit der linken Seite durchgeführt werden kann, was Int?auf den optionalen Verkettungsaufruf zurückzuführen ist.

In ähnlicher Weise könnten Sie Folgendes tun:

if array?.isEmpty == false {
    print("There are objects")
} else {
    print("No objects")
}

Hinweis: Damit falsedies funktioniert, müssen Sie explizit mit hier vergleichen .


Wenn Sie etwas tun möchten, wenn das Array nilleer ist oder ist, haben Sie mindestens 7 Möglichkeiten:

Option A:

if !(array?.count > 0) {
    print("There are no objects")
}

Option B:

if !(array?.isEmpty == false) {
    print("There are no objects")
}

Option C:

if array == nil || array!.count == 0 {
    print("There are no objects")
}

Option D:

if array == nil || array!.isEmpty {
    print("There are no objects")
}

Option E:

if (array ?? []).isEmpty {
    print("There are no objects")
}

Option F:

if array?.isEmpty ?? true {
    print("There are no objects")
}

Option G:

if (array?.count ?? 0) == 0 {
    print("There are no objects")
}

Option D erfasst genau, wie Sie es auf Englisch beschrieben haben: "Ich möchte etwas Besonderes nur tun, wenn es null oder leer ist." Ich würde empfehlen, dass Sie dies verwenden, da es leicht zu verstehen ist. Daran ist nichts auszusetzen, zumal es "kurzschließt" und die Prüfung auf leer überspringt, wenn die Variable ist nil.

vacawama
quelle
2
Das funktioniert. Nur der Vollständigkeit halber: Es wird der func ><T : _Comparable>(lhs: T?, rhs: T?) -> BoolOperator verwendet und die rechte Seite 0wird Int?vom Compiler in einen eingeschlossen .
Martin R
1
Mir ist gerade aufgefallen, dass mit var opt : Int? = nil, opt < 0bewertet true. Es ist hier nicht relevant , sondern kann unerwartet sein, und kann ein Argument gegen den Vergleich optional ganze Zahlen.
Martin R
nilist kleiner als jeder Nicht-Null-Wert, den IntSie darauf werfen, auch negative. Es muss sich an dem einen oder anderen Ende des umschlossenen Typs befinden, da jede Implementierung von <eine Gesamtreihenfolge sein muss und optional jeden vergleichbaren Typ umschließen kann. Ich denke, nichts weniger als alles andere ist intuitiv, denn wenn jemand eine Spalte mit Zahlen sortiert, die leer sein könnte, würde er erwarten, dass die Leerzeichen vor 1 stehen. Oder alternativ ist eine Null-Array-Variable noch leerer als eine leere Array :)
Fluggeschwindigkeit Velocity
Danke, @vacawama. Die Option, auf die Sie hingewiesen haben, funktioniert. Ich ging jedoch etwas weiter und versuchte es mit einem anderen speziellen Fall: Ich testete nur, ob das Array null oder leer ist, unabhängig davon, ob ich etwas tue, wenn es Elemente enthält. Ich werde meine Frage bearbeiten, damit Sie sie sich ansehen können.
eze.scaruli
2
@ Rambatino, !(array?.isEmpty == false)wird sein, truewenn arrayist nil, aber array?.isEmpty == truewird sein, falsewenn arrayist, nilweil nilnicht gleich ist true. Wir wollen ein nil arrayals leer behandeln.
Vacawama
8

Erweiterungseigenschaft im CollectionProtokoll

* Geschrieben in Swift 3

extension Optional where Wrapped: Collection {
    var isNilOrEmpty: Bool {
        switch self {
            case .some(let collection):
                return collection.isEmpty
            case .none:
                return true
        }
    }
}

Beispiel Verwendung:

if array.isNilOrEmpty {
    print("The array is nil or empty")
}

 

Andere Optionen

Abgesehen von der obigen Erweiterung finde ich die folgende Option am klarsten, ohne das gewaltsame Auspacken von Optionen zu erzwingen. Ich habe dies als Auspacken des optionalen Arrays und als Ersatz für ein leeres Array des gleichen Typs gelesen. Nehmen Sie dann das (nicht optionale) Ergebnis und isEmptyführen Sie den bedingten Code aus.

Empfohlen

if (array ?? []).isEmpty {
    print("The array is nil or empty")
}

Obwohl das Folgende klar liest, schlage ich die Gewohnheit vor, das Auspacken von Optionen nach Möglichkeit zu vermeiden. Obwohl Sie garantiert , dass arrayniemals sein wird, nilwenn array!.isEmptyin diesem speziellen Fall ausgeführt wird, wäre es später leicht zu bearbeiten sein und versehentlich einen Absturz bringen. Wenn Sie es sich bequem machen, Optionen zum Auspacken zu erzwingen, erhöhen Sie die Wahrscheinlichkeit, dass jemand in Zukunft eine Änderung vornimmt, die kompiliert, aber zur Laufzeit abstürzt.

Nicht empfohlen!

if array == nil || array!.isEmpty {
    print("The array is nil or empty")
}

Ich finde Optionen, die array?(optionale Verkettung) enthalten, verwirrend wie:

Verwirrend?

if !(array?.isEmpty == false) {
    print("The array is nil or empty")
}

if array?.isEmpty ?? true {
    print("There are no objects")
}
Mobiler Dan
quelle
5

Option D: Wenn das Array nicht optional sein muss, weil es Ihnen nur wichtig ist, ob es leer ist oder nicht, initialisieren Sie es als leeres Array anstelle eines optionalen:

var array = [Int]()

Jetzt wird es immer existieren und Sie können einfach nachsehen isEmpty.

jrturton
quelle
Obwohl ich damit einverstanden bin, ist das Problem, dass wir nicht genau wissen, was das OP will. Abhängig von der verwendeten API ist es möglich, dass ein Array entweder Inhalt hat oder Null ist. Oder ist null, leer oder enthält Werte. Und jede dieser Situationen hat unterschiedliche Lösungen.
Abizern
Ich stimmte zu, ich präsentierte nur eine Option, die ich persönlich nützlich fand.
Jrturton
1
Lol ja. Ich habe genau das kommentiert, bevor ich Ihre Antwort gelesen habe. Großartige Köpfe ... :-)
Fogmeister
Tabellenansichten sind genau die Situation, an die ich denke!
Jrturton
5

Swift 3-4 kompatibel:

extension Optional where Wrapped: Collection {
        var nilIfEmpty: Optional {
            switch self {
            case .some(let collection):
                return collection.isEmpty ? nil : collection
            default:
                return nil
            }
        }

        var isNilOrEmpty: Bool {
            switch self {
            case .some(let collection):
                return collection.isEmpty
            case .none:
                return true
        }
}

Verwendung:

guard let array = myObject?.array.nilIfEmpty else { return }

Oder

if myObject.array.isNilOrEmpty {
    // Do stuff here
}
Löwe
quelle
3

Bedingtes Auspacken:

if let anArray = array {
    if !anArray.isEmpty {
        //do something
    }
}

EDIT: Möglich seit Swift 1.2:

if let myArray = array where !myArray.isEmpty {
    // do something with non empty 'myArray'
}

EDIT: Möglich seit Swift 2.0:

guard let myArray = array where !myArray.isEmpty else {
    return
}
// do something with non empty 'myArray'
Borchero
quelle
Er muss noch prüfen, ob es leer ist oder nicht. Dies prüft nur, ob das optionale ein Array enthält.
Abizern
Ja, dann können Sie tunif array? != nil && !(array!.isEmpty) {}
Borchero
Sie können es einfach auspacken, da die Zeile nicht ausgeführt wird, wenn das Array Null ist und nicht ausgepackt werden kann
Borchero
1
Denken Sie nicht, dass Sie schreiben müssen array?und array!in derselben Zeile stehen müssen, um ein Codegeruch zu sein? Dafür ist das bedingte Auspacken gedacht.
Abizern
Aber pass auf, du musst den logischen Operator & verwenden -> du musst && anstelle von & verwenden. Andernfalls könnten Sie eine Fehlermeldung erhalten , wenn das Array null ist
borchero
1

Die elegante integrierte Lösung ist die mapMethode von Optional . Diese Methode wird oft vergessen, macht aber genau das, was Sie hier brauchen. Sie können damit sicher eine Nachricht an das Objekt senden, das in einem optionalen Objekt verpackt ist. In diesem Fall erhalten wir eine Art Drei-Wege-Schalter: Wir können isEmptyzum optionalen Array sagen und wahr, falsch oder null werden (falls das Array selbst null ist).

var array : [Int]?
array.map {$0.isEmpty} // nil (because `array` is nil)
array = []
array.map {$0.isEmpty} // true (wrapped in an Optional)
array?.append(1)
array.map {$0.isEmpty} // false (wrapped in an Optional)
matt
quelle
0

Anstatt zu verwenden ifund elsees ist besser, nur nach guardleeren Arrays zu suchen, ohne neue Variablen für dasselbe Array zu erstellen.

guard !array.isEmpty else {
    return
}
// do something with non empty ‘array’
Phil
quelle
Eine Erklärung mit Code verbessert die Qualität der Antwort.
Dipali Shah
1
Eine gute Antwort hat eine bessere Erklärung Wie schreibe ich eine gute Antwort?
Narendra Jadhav