Comment retourner les 5 premiers objets de Array dans Swift?

179

Dans Swift, existe-t-il une manière intelligente d'utiliser les méthodes d'ordre supérieur sur Array pour renvoyer les 5 premiers objets? La manière obj-c de le faire était de sauvegarder un index et de faire une boucle for à travers le tableau en incrémentant l'index jusqu'à ce qu'il soit 5 et en renvoyant le nouveau tableau. Y a-t-il un moyen de faire cela avec filter, mapou reduce?

bogen
la source
Voir ma réponse pour Swift 4 qui montre jusqu'à 6 façons différentes de retourner les premiers néléments d'un fichier Array.
Imanou Petit

Réponses:

446

De loin, le moyen le plus simple d'obtenir les N premiers éléments d'un tableau Swift est d'utiliser prefix(_ maxLength: Int):

let someArray = [1, 2, 3, 4, 5, 6, 7]
let first5 = someArray.prefix(5) // 1, 2, 3, 4, 5

Cela a l'avantage d'être sûrs. Si le nombre que vous passez prefixest supérieur au nombre de tableaux, il renvoie simplement le tableau entier.

REMARQUE: comme indiqué dans les commentaires, Array.prefixrenvoie en fait un ArraySlice, pas un Array. Dans la plupart des cas, cela ne devrait pas faire de différence, mais si vous devez attribuer le résultat à un Arraytype ou le transmettre à une méthode qui attend un Arrayparamètre, vous devrez forcer le résultat dans un Arraytype:let first5 = Array(someArray.prefix(5))

mluisbrown
la source
42
+1 un si mauvais choix de nom, à mon humble avis. Array a dropFirstet dropLast, pourrait aussi bien avoir takeFirstet takeLast.
Mazyod
10
Aussi si vous avez besoin first5d'être un tableau, écrivez simplementlet first5 = Array(someArray.prefix(5))
ULazdins
2
@mluisbrown Désolé, je ne suis pas d'accord avec vous :) Dans mon projet video = video.prefix(5)dans Xcode 7.2 entraîne une erreur de compilation Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins
5
video = Array(video.prefix(5))
Bartłomiej Semańczyk
2
@ onmyway133 prefixest peut-être seulement Swift 2.x (je ne me souviens pas si c'était en 1.x), mais il existe certainement dans tout système d'exploitation prenant en charge Swift 2.x, qui est iOS 7 et supérieur. La disponibilité des fonctionnalités Swift est déterminée par les versions Swift, et non par les versions iOS.
mluisbrown
99

Mise à jour: Il y a maintenant la possibilité d'utiliser prefixpour obtenir les n premiers éléments d'un tableau. Consultez la réponse de @ mluisbrown pour savoir comment utiliser le préfixe.

Réponse d' origine: Vous pouvez le faire vraiment facile sans filter, mapou reducesimplement en retournant une gamme de votre tableau:

var wholeArray = [1, 2, 3, 4, 5, 6]
var n = 5

var firstFive = wholeArray[0..<n] // 1,2,3,4,5
Christian
la source
71
Si vous ne voulez que les premiers néléments d'un tableau Swift, vous pouvez le faire, wholeArray.prefix(n)ce qui présente l'avantage supplémentaire d'être en sécurité. Si nest plus grand que la taille du tableau prefixrenvoie le tableau entier.
mluisbrown
4
Il plantera si le wholeArrayn'a pas plus d'éléments quen
Jake Lin
@Crashalot Je ne suis pas tout à fait sûr, mais je pense qu'à l'époque, où j'ai écrit ma réponse, il n'existait pas prefix.
Christian
1
Utilisez ce code pour obtenir les 5 premiers objets ... Cela fonctionne parfaitement [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: nil}
Manish Mahajan
64

Avec Swift 5, selon vos besoins, vous pouvez choisir l'un des 6 codes Playground suivants afin de résoudre votre problème.


#1. Utilisation de l' subscript(_:)indice

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array[..<5]
//let arraySlice = array[0..<5] // also works
//let arraySlice = array[0...4] // also works
//let arraySlice = array[...4] // also works
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

# 2. Utilisation de la prefix(_:)méthode

Complexité: O (1) si la collection est conforme à RandomAccessCollection; sinon, O ( k ), où k est le nombre d'éléments à sélectionner au début de la collection.

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(5)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

Apple déclare pour prefix(_:):

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.


# 3. Utilisation de la prefix(upTo:)méthode

Complexité: O (1)

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(upTo: 5)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

Apple déclare pour prefix(upTo:):

L'utilisation de la prefix(upTo:)méthode équivaut à utiliser une plage semi-ouverte partielle comme indice de la collection. La notation en indice est préférable à prefix(upTo:).


# 4. Utilisation de la prefix(through:)méthode

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let arraySlice = array.prefix(through: 4)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]

# 5. Utilisation de la removeSubrange(_:)méthode

Complexité: O ( n ), où n est la longueur de la collection.

var array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
array.removeSubrange(5...)
print(array) // prints: ["A", "B", "C", "D", "E"]

# 6. Utilisation de la dropLast(_:)méthode

Complexité: O (1) si la collection est conforme à RandomAccessCollection; sinon, O ( k ), où k est le nombre d'éléments à supprimer.

let array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
let distance = array.distance(from: 5, to: array.endIndex)
let arraySlice = array.dropLast(distance)
let newArray = Array(arraySlice)
print(newArray) // prints: ["A", "B", "C", "D", "E"]
Imanou Petit
la source
28
let a: [Int] = [0, 0, 1, 1, 2, 2, 3, 3, 4]
let b: [Int] = Array(a.prefix(5))
// result is [0, 0, 1, 1, 2]
neoneye
la source
18

SWIFT 4

Une solution différente:

Une solution en ligne simple qui ne plantera pas si votre baie est trop courte

[0,1,2,3,4,5].enumerated().compactMap{ $0.offset < 3 ? $0.element : nil }

Mais fonctionne bien avec cela.

[0,1,2,3,4,5].enumerated().compactMap{ $0.offset < 1000 ? $0.element : nil }

Habituellement, cela planterait si vous faisiez ceci:

[0,1,2,3,4,5].prefix(upTo: 1000) // THIS CRASHES

[0,1,2,3,4,5].prefix(1000) // THIS DOESNT
David Rees
la source
3
pour swift3[0,1,2,3,4,5].enumerated().flatMap{ $0.offset < 1000 ? $0.element : nil }
StevenTsooo
1
Merci! Si vous souhaitez mettre à jour, flatMap s'appelle désormais compactMap dans Swift 4 pour le compactage de tableaux.
manmal
14

Pour obtenir les 5 premiers éléments d'un tableau, tout ce que vous avez à faire est de découper le tableau en question. Dans Swift, vous le faites comme ceci: array[0..<5].

Pour rendre le choix des N premiers éléments d'un tableau un peu plus fonctionnel et généralisable, vous pouvez créer une méthode d'extension pour le faire. Par exemple:

extension Array {
    func takeElements(var elementCount: Int) -> Array {
        if (elementCount > count) {
            elementCount = count
        }
        return Array(self[0..<elementCount])
    }
}
Markus
la source
5

J'ai légèrement modifié la réponse de Markus pour la mettre à jour pour la dernière version de Swift, car à l' varintérieur de votre déclaration de méthode n'est plus prise en charge:

extension Array {
    func takeElements(elementCount: Int) -> Array {
        if (elementCount > count) {
            return Array(self[0..<count])
        }
        return Array(self[0..<elementCount])
    }
}
Antoine
la source
3

Swift 4

Pour obtenir les N premiers éléments d'un tableau Swift, vous pouvez utiliser prefix(_ maxLength: Int):

Array(largeArray.prefix(5))
inquiétant
la source
1

Swift 4 avec sauvegarde des types de tableaux

extension Array {
    func take(_ elementsCount: Int) -> [Element] {
        let min = Swift.min(elementsCount, count)
        return Array(self[0..<min])
    }
}
Pavel Shorokhov
la source
1

Mise à jour pour Swift 4:

[0,1,2,3,4,5].enumerated().compactMap{ $0 < 10000 ? $1 : nil }

Pour Swift 3:

[0,1,2,3,4,5].enumerated().flatMap{ $0 < 10000 ? $1 : nil }
mkkrolik
la source
1
Solution inefficace. 1) Vous créez une séquence supplémentaire de longueur d'un tableau. 2) Vous parcourez tous les éléments.
Alexander Bekert
2
10000? Qu'est-ce que c'est?
BangOperator
1

Plain & Simple

extension Array {
    func first(elementCount: Int) -> Array {
          let min = Swift.min(elementCount, count)
          return Array(self[0..<min])
    }
}
Abhishek Bedi
la source
1

Pour un tableau d'objets, vous pouvez créer une extension à partir de Sequence.

extension Sequence {
    func limit(_ max: Int) -> [Element] {
        return self.enumerated()
            .filter { $0.offset < max }
            .map { $0.element }
    }
}

Usage:

struct Apple {}

let apples: [Apple] = [Apple(), Apple(), Apple()]
let limitTwoApples = apples.limit(2)

// limitTwoApples: [Apple(), Apple()]
Leo Valentim
la source