Nouvelle matrice de la gamme d'index Swift

122

Comment puis-je faire quelque chose comme ça? Prenez les n premiers éléments d'un tableau:

newNumbers = numbers[0..n]

Obtient actuellement l'erreur suivante:

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

ÉDITER:

Voici la fonction dans laquelle je travaille.

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

Réponses:

181

Cela fonctionne pour moi:

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

Votre problème peut être lié à la façon dont vous déclarez votre tableau pour commencer.

ÉDITER:

Pour corriger votre fonction, vous devez convertir votre Sliceen tableau:

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
la source
J'ai ajouté un peu plus de contexte à ma question, je travaille dans une fonction. Cela fonctionne indépendamment, mais pas à l'intérieur de la fonction.
Charlie Egan le
1
Charmant! Cheers - cela fonctionne. J'accepterai la réponse quand elle me le permettra.
Charlie Egan
23
Point pédant, mais il ne s'agit pas vraiment de convertir le Sliceen un Array, mais plutôt de créer un nouveau tableau à partir d'une tranche. Un casting utiliserait l' asopérateur: numbers as Arrayce qui entraînerait une erreur.
jb
Le langage a changé, il utilise trois points de suspension et non deux developer.apple.com/library/ios/documentation/General/Reference/...
Daniel Galasko
2
Les deux points ont ..changé en ..<; les trois points (une ellipse) sont restés les mêmes. Merci pour le rappel, cependant; J'ai mis à jour la réponse.
Cezary Wojcik
100

#1. Utilisation de l' Arrayindice avec plage

Avec Swift 5, lorsque vous écrivez…

let newNumbers = numbers[0...position]

newNumbersN'est pas de type Array<Int>mais est de type ArraySlice<Int>. C'est parce que Arrayles subscript(_:​)retours et ArraySlice<Element>qui, selon Apple, présentent une vue sur le stockage d'une plus grande baie.

En outre, Swift fournit également Arrayun initialiseur appelé init(_:​)qui nous permet de créer un nouveau tableau à partir d'un sequence(y compris ArraySlice).

Par conséquent, vous pouvez utiliser subscript(_:​)avec init(_:​)pour obtenir un nouveau tableau à partir des n premiers éléments d'un tableau:

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. Utilisation de Arrayla prefix(_:)méthode de

Swift fournit une prefix(_:)méthode pour les types conformes au Collectionprotocole (y compris Array). prefix(_:)a la déclaration suivante:

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

Renvoie une sous-séquence, jusqu'à maxLength en longueur, contenant les éléments initiaux.

Apple déclare également:

Si la longueur maximale dépasse le nombre d'éléments de la collection, le résultat contient tous les éléments de la collection.

Par conséquent, comme alternative à l'exemple précédent, vous pouvez utiliser le code suivant afin de créer un nouveau tableau à partir des premiers éléments d'un autre tableau:

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
la source
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
la source
veuillez également ajouter une description à la réponse.
Naman
Très belle réponse. Ce qu'il fait essentiellement, c'est qu'il convertit un ArraySlice <T> en un Array. Personnellement, je n'inclurais pas autant d'affirmations. Comme je veux généralement que la tranche échoue si je fournis de fausses plages, etc.
eonist
0

Une autre variante utilisant un extensionnom d'argumentrange

Cette extension utilise RangeetClosedRange

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
la source
0

Array manière fonctionnelle:

   array.enumerated().filter { $0.offset < limit }.map { $0.element }

varié:

 array.enumerated().filter { $0.offset >= minLimit && $0.offset < maxLimit }.map { $0.element }

L'avantage de cette méthode est qu'une telle mise en œuvre est sûre.

Vyacheslav
la source