¿Cómo devolver los primeros 5 objetos de Array en Swift?

179

En Swift, ¿hay una manera inteligente de usar los métodos de orden superior en Array para devolver los 5 primeros objetos? La forma obj-c de hacerlo fue guardar un índice y for-loop a través del índice incremental de la matriz hasta que fue 5 y devolvió la nueva matriz. ¿Hay una manera de hacer esto con filter, mapo reduce?

bogen
fuente
Vea mi respuesta para Swift 4 que muestra hasta 6 formas diferentes de devolver los primeros nelementos de un Array.
Imanou Petit

Respuestas:

446

Con mucho, la forma más perfecta de obtener los primeros N elementos de una matriz Swift es usar prefix(_ maxLength: Int):

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

Esto tiene el beneficio de estar a salvo. Si el recuento al que pasa prefixes mayor que el recuento de la matriz, entonces solo devuelve toda la matriz.

NOTA: como se señaló en los comentarios, en Array.prefixrealidad devuelve un ArraySlice, no un Array. En la mayoría de los casos, esto no debería marcar la diferencia, pero si necesita asignar el resultado a un Arraytipo o pasarlo a un método que espera un Arrayparámetro, deberá forzar el resultado a un Arraytipo:let first5 = Array(someArray.prefix(5))

mluisbrown
fuente
42
+1 una elección de mal nombre, en mi humilde opinión. Array tiene dropFirsty dropLast, también podría tener takeFirsty takeLast.
Mazyod
10
Además, si necesita first5ser una matriz, simplemente escribalet first5 = Array(someArray.prefix(5))
ULazdins
2
@mluisbrown Lo siento, no puedo estar de acuerdo contigo :) En mi proyecto video = video.prefix(5)en Xcode 7.2 se produce un error de compilación Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins
55
video = Array(video.prefix(5))
Bartłomiej Semańczyk
2
@ onmyway133 prefixes posiblemente solo Swift 2.x (no recuerdo si estaba en 1.x), pero ciertamente existe en cualquier sistema operativo que soporte Swift 2.x, que es iOS 7 y superior. La disponibilidad de la función Swift está determinada por las versiones de Swift, no por las versiones de iOS.
mluisbrown
99

Actualización: ahora existe la posibilidad de usar prefixpara obtener los primeros n elementos de una matriz. Verifique la respuesta de @ mluisbrown para obtener una explicación sobre cómo usar el prefijo.

Respuesta original: puede hacerlo realmente fácil sin filter, mapo reducesimplemente devolviendo un rango de su matriz:

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

var firstFive = wholeArray[0..<n] // 1,2,3,4,5
cristiano
fuente
71
Si desea solo los primeros nelementos de una matriz Swift, puede hacerlo, lo wholeArray.prefix(n)que tiene el beneficio adicional de ser seguro. Si nes mayor que el tamaño de la matriz, prefixdevuelve toda la matriz.
mluisbrown
44
Se bloqueará si wholeArrayno tiene más elementos quen
Jake Lin
@Crashalot No estoy completamente seguro, pero creo que en ese momento, donde escribí mi respuesta, no había tal cosa como prefix.
Christian
1
Use este código para obtener los primeros 5 objetos ... Esto funciona perfectamente [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: cero}
Manish Mahajan
64

Con Swift 5, de acuerdo con sus necesidades, puede elegir uno de los 6 siguientes códigos de Playground para resolver su problema.


# 1 Usando subscript(_:)subíndice

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 Utilizandoprefix(_:) método

Complejidad: O (1) si la colección se ajusta a RandomAccessCollection; de lo contrario, O ( k ), donde k es el número de elementos para seleccionar desde el comienzo de la colección.

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 declara para prefix(_:):

Si la longitud máxima excede el número de elementos en la colección, el resultado contiene todos los elementos en la colección.


# 3 Utilizandoprefix(upTo:) método

Complejidad: 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 declara para prefix(upTo:):

Usar el prefix(upTo:)método es equivalente a usar un rango medio abierto parcial como subíndice de la colección. Se prefiere la notación de subíndice sobre prefix(upTo:).


# 4. Utilizando el prefix(through:)método

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. Utilizando el removeSubrange(_:)método

Complejidad: O ( n ), donde n es la longitud de la colección.

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. Utilizando el dropLast(_:)método

Complejidad: O (1) si la colección se ajusta a RandomAccessCollection; de lo contrario, O ( k ), donde k es el número de elementos a soltar.

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
fuente
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
fuente
18

SWIFT 4

Una solución diferente:

Una solución en línea fácil que no se bloqueará si su matriz es demasiado corta

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

Pero funciona bien con esto.

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

Por lo general, esto se bloquearía si hicieras esto:

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

[0,1,2,3,4,5].prefix(1000) // THIS DOESNT
David Rees
fuente
3
para swift3[0,1,2,3,4,5].enumerated().flatMap{ $0.offset < 1000 ? $0.element : nil }
StevenTsooo
1
¡Gracias! En caso de que desee actualizar, flatMap ahora se llama compactMap en Swift 4 para la compactación de matrices.
manmal
14

Para obtener los primeros 5 elementos de una matriz, todo lo que necesita hacer es cortar la matriz en cuestión. En Swift, lo haces así:array[0..<5] .

Para que elegir los N primeros elementos de una matriz sea un poco más funcional y generalizable, puede crear un método de extensión para hacerlo. Por ejemplo:

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

Cambié ligeramente la respuesta de Markus para actualizarla para la última versión de Swift, como var la declaración dentro de su método ya no es compatible:

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

Swift 4

Para obtener los primeros N elementos de una matriz Swift puede usar prefix(_ maxLength: Int):

Array(largeArray.prefix(5))
malicioso
fuente
1

Swift 4 con guardar tipos de matriz

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

Actualización para swift 4:

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

Para Swift 3:

[0,1,2,3,4,5].enumerated().flatMap{ $0 < 10000 ? $1 : nil }
mkkrolik
fuente
1
Solución ineficaz. 1) Crea una secuencia adicional de longitud de una matriz. 2) Usted itera a través de todos los elementos.
Alexander Bekert
2
10000? ¿Que es eso?
BangOperator
1

Llano y simple

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

Para una matriz de objetos, puede crear una extensión desde Secuencia.

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()]
Leo Valentim
fuente