Neues Array aus dem Indexbereich Swift

122

Wie kann ich so etwas machen? Nehmen Sie die ersten n Elemente aus einem Array:

newNumbers = numbers[0..n]

Derzeit wird der folgende Fehler angezeigt:

error: could not find an overload for 'subscript' that accepts the supplied arguments

BEARBEITEN:

Hier ist die Funktion, in der ich arbeite.

func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
    var newNumbers = numbers[0...position]
    return newNumbers
}
Charlie Egan
quelle

Antworten:

179

Das funktioniert bei mir:

var test = [1, 2, 3]
var n = 2
var test2 = test[0..<n]

Ihr Problem könnte darin bestehen, wie Sie Ihr Array zunächst deklarieren.

BEARBEITEN:

Um Ihre Funktion zu reparieren, müssen Sie Ihre Slicein ein Array umwandeln:

func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
    var newNumbers = Array(numbers[0..<position])
    return newNumbers
}

// test
aFunction([1, 2, 3], 2) // returns [1, 2]
Cezary Wojcik
quelle
Ich habe meiner Frage etwas mehr Kontext hinzugefügt, ich arbeite in einer Funktion. Dies funktioniert unabhängig, jedoch nicht innerhalb der Funktion.
Charlie Egan
1
Schön! Prost - das funktioniert. Ich werde die Antwort akzeptieren, wenn es mir erlaubt.
Charlie Egan
23
Pedantisch Punkt, aber das ist nicht wirklich Gießen der Sliceauf ein Array, sondern ein neues Array von einer Scheibe zu schaffen. Eine Besetzung würde den asOperator verwenden, numbers as Arraywas zu einem Fehler führen würde.
jb
Die Sprache hat sich geändert, sie verwendet drei Auslassungspunkte und nicht zwei developer.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko
2
Die zwei Punkte ..änderten sich zu ..<; Die drei Punkte (eine Ellipse) sind gleich geblieben. Vielen Dank für die Erinnerung; Ich habe die Antwort aktualisiert.
Cezary Wojcik
100

# 1. Mit ArrayIndex mit Bereich

Mit Swift 5, wenn Sie schreiben ...

let newNumbers = numbers[0...position]

newNumbersIst nicht vom Typ, Array<Int>sondern vom Typ ArraySlice<Int>. Das liegt daran Array, dass es subscript(_:​)eine Rückgabe gibt ArraySlice<Element>, die laut Apple einen Blick auf den Speicher eines größeren Arrays bietet.

Außerdem bietet Swift auch Arrayeinen Initialisierer namens init(_:​), der es uns ermöglicht, ein neues Array aus einem sequence(einschließlich ArraySlice) zu erstellen .

Daher können Sie subscript(_:​)mit init(_:​)verwenden, um ein neues Array aus den ersten n Elementen eines Arrays zu erhalten:

let array = Array(10...14) // [10, 11, 12, 13, 14]
let arraySlice = array[0..<3] // using Range
//let arraySlice = array[0...2] // using ClosedRange also works
//let arraySlice = array[..<3] // using PartialRangeUpTo also works
//let arraySlice = array[...2] // using PartialRangeThrough also works
let newArray = Array(arraySlice)
print(newArray) // prints [10, 11, 12]

# 2. Mit Arrayder prefix(_:)Methode von

Swift bietet eine prefix(_:)Methode für Typen, die dem CollectionProtokoll entsprechen (einschließlich Array). prefix(_:)hat die folgende Erklärung:

func prefix(_ maxLength: Int) -> ArraySlice<Element>

Gibt eine Teilsequenz mit einer Länge von bis zu maxLength zurück, die die Anfangselemente enthält.

Apple sagt auch:

Wenn die maximale Länge die Anzahl der Elemente in der Sammlung überschreitet, enthält das Ergebnis alle Elemente in der Sammlung.

Daher können Sie alternativ zum vorherigen Beispiel den folgenden Code verwenden, um aus den ersten Elementen eines anderen Arrays ein neues Array zu erstellen:

let array = Array(10...14) // [10, 11, 12, 13, 14]
let arraySlice = array.prefix(3)
let newArray = Array(arraySlice)
print(newArray) // prints [10, 11, 12]
Imanou Petit
quelle
7
func subArray<T>(array: [T], range: NSRange) -> [T] {
  if range.location > array.count {
    return []
  }
  return Array(array[range.location..<min(range.length, array.count)])
}
Phil
quelle
Bitte fügen Sie der Antwort auch eine Beschreibung hinzu.
Naman
Sehr schöne Antwort. Im Wesentlichen wird ein ArraySlice <T> in ein Array umgewandelt. Persönlich würde ich nicht so viele Behauptungen aufnehmen. Da ich normalerweise möchte, dass Slice fehlschlägt, wenn ich falsche Bereiche usw.
bereitstelle
0

Eine weitere Variante mit extensionund Argumentnamerange

Diese Erweiterung verwendet RangeundClosedRange

extension Array {

    subscript (range r: Range<Int>) -> Array {
        return Array(self[r])
    }


    subscript (range r: ClosedRange<Int>) -> Array {
        return Array(self[r])
    }
}

Tests:

func testArraySubscriptRange() {
    //given
    let arr = ["1", "2", "3"]

    //when
    let result = arr[range: 1..<arr.count] as Array

    //then
    XCTAssertEqual(["2", "3"], result)
}

func testArraySubscriptClosedRange() {
    //given
    let arr = ["1", "2", "3"]

    //when
    let result = arr[range: 1...arr.count - 1] as Array

    //then
    XCTAssertEqual(["2", "3"], result)
}
yoAlex5
quelle