Come restituire i primi 5 oggetti di Array in Swift?


179

In Swift, c'è un modo intelligente di usare i metodi di ordine superiore su Array per restituire i primi 5 oggetti? Il modo obj-c per farlo era il salvataggio di un indice e il for-loop attraverso l'indice di incremento dell'array fino a quando era 5 e restituendo il nuovo array. C'è un modo per fare questo con filter, mapo reduce?


Vedi la mia risposta per Swift 4 che mostra fino a 6 modi diversi per restituire i primi nelementi di un Array.
Imanou Petit,

Risposte:


446

Di gran lunga il modo più semplice per ottenere i primi N elementi di un array Swift sta usando prefix(_ maxLength: Int):

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

Questo ha il vantaggio di essere al sicuro. Se il conteggio a cui si passa prefixè maggiore del conteggio degli array, restituisce semplicemente l'intero array.

NOTA: come sottolineato nei commenti, Array.prefixrestituisce effettivamente un ArraySlice, non un Array. Nella maggior parte dei casi ciò non dovrebbe fare la differenza, ma se è necessario assegnare il risultato a un Arraytipo o passarlo a un metodo che prevede un Arrayparametro, è necessario forzare il risultato in un Arraytipo:let first5 = Array(someArray.prefix(5))


42
+1 una scelta così cattiva, IMHO. L'array ha dropFirste dropLast, quindi potrebbe anche avere takeFirste takeLast.
Mazyod,

10
Inoltre, se devi first5essere un array, scrivilet first5 = Array(someArray.prefix(5))
ULazdins l'

2
@mluisbrown Siamo spiacenti, non posso essere d'accordo con te :) Nel mio progetto video = video.prefix(5)in Xcode 7.2 risulta un errore di compilazione Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins,

5
video = Array(video.prefix(5))
Bartłomiej Semańczyk,

2
@ onmyway133 prefixè probabilmente solo Swift 2.x (non ricordo se fosse in 1.x), ma esiste sicuramente in qualsiasi sistema operativo che supporti Swift 2.x, che è iOS 7 e versioni successive. La disponibilità delle funzionalità di Swift è determinata dalle versioni di Swift, non dalle versioni di iOS.
mluisbrown,

99

Aggiornamento: ora è possibile utilizzare prefixper ottenere i primi n elementi di un array. Controlla la risposta di @ mluisbrown per una spiegazione su come usare il prefisso.

Risposta originale: puoi farlo davvero facilmente senza filter, mapo reducesemplicemente restituendo una gamma del tuo array:

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

var firstFive = wholeArray[0..<n] // 1,2,3,4,5

71
Se desideri solo i primi nelementi di un array Swift, puoi fare ciò wholeArray.prefix(n)che ha l'ulteriore vantaggio di essere sicuro ai limiti. Se nè maggiore della dimensione dell'array prefixrestituisce l'intero array.
Mluisbrown,

4
Andrà in crash se wholeArraynon ha più elementi din
Jake Lin

@Crashalot Non sono del tutto sicuro, ma penso che al momento, in cui ho scritto la mia risposta, non esistesse nulla del genere prefix.
Christian

1
Usa questo codice per ottenere i primi 5 oggetti ... Funziona perfettamente [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: zero}
Manish Mahajan

64

Con Swift 5, in base alle tue esigenze, puoi scegliere uno dei 6 seguenti codici Playground per risolvere il tuo problema.


# 1. Usando il subscript(_:)pedice

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. Usando il prefix(_:)metodo

Complessità: O (1) se la raccolta è conforme RandomAccessCollection; in caso contrario, O ( k ), dove k è il numero di elementi da selezionare dall'inizio della raccolta.

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 afferma per prefix(_:):

Se la lunghezza massima supera il numero di elementi nella raccolta, il risultato contiene tutti gli elementi nella raccolta.


# 3. Usando il prefix(upTo:)metodo

Complessità: 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 afferma per prefix(upTo:):

L'uso del prefix(upTo:)metodo equivale all'utilizzo di un intervallo parziale parzialmente aperto come indice della raccolta. La notazione in pedice è preferita prefix(upTo:).


# 4. Usando il prefix(through:)metodo

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. Usando il removeSubrange(_:)metodo

Complessità: O ( n ), dove n è la lunghezza della raccolta.

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. Usando il dropLast(_:)metodo

Complessità: O (1) se la raccolta è conforme RandomAccessCollection; altrimenti, O ( k ), dove k è il numero di elementi da eliminare.

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"]

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]

18

SWIFT 4

Una soluzione diversa:

Una soluzione inline semplice che non si arresta in modo anomalo se l'array è troppo corto

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

Ma funziona bene con questo.

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

Di solito questo si bloccherebbe se lo facessi:

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

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

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

1
Grazie! Nel caso in cui si desideri aggiornare, flatMap viene ora chiamato compactMap in Swift 4 per la compattazione dell'array.
manmal

14

Per ottenere i primi 5 elementi di un array, tutto ciò che devi fare è dividere l'array in questione. In Swift, lo si fa in questo modo: array[0..<5].

Per rendere la raccolta degli N primi elementi di un array un po 'più funzionale e generalizzabile, è possibile creare un metodo di estensione per farlo. Per esempio:

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

5

Ho leggermente modificato la risposta di Markus per aggiornarla per l'ultima versione di Swift, in quanto varla dichiarazione del metodo non è più supportata:

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

3

Swift 4

Per ottenere i primi N elementi di un array Swift è possibile utilizzare prefix(_ maxLength: Int):

Array(largeArray.prefix(5))

1

Swift 4 con salvataggio dei tipi di array

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

1

Aggiornamento per swift 4:

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

Per swift 3:

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

1
Soluzione inefficace. 1) Si crea una sequenza aggiuntiva di lunghezza di un array. 2) Esamini tutti gli elementi.
Alexander Bekert,

2
10000? Cos'è quello?
BangOperator,

1

Semplice e chiaro

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

1

Per una matrice di oggetti è possibile creare un'estensione da Sequenza.

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

Uso:

struct Apple {}

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

// limitTwoApples: [Apple(), Apple()]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.