¿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?


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))


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

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

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

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])
    }
}

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])
    }
}

3

Swift 4

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

Array(largeArray.prefix(5))

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])
    }
}

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 }

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])
    }
}

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()]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.