Como retornar os 5 primeiros objetos da Matriz no Swift?

178

No Swift, existe uma maneira inteligente de usar os métodos de ordem superior no Array para retornar os 5 primeiros objetos? A maneira obj-c de fazer isso era salvar um índice e fazer um loop for através do índice, incrementando o índice até os 5 anos e retornando o novo array. Existe uma maneira de fazer isso com filter, mapou reduce?

bogen
fonte
Veja minha resposta para o Swift 4, que mostra até 6 maneiras diferentes de retornar os primeiros nelementos de um Array.
Imanou Petit 07/07

Respostas:

441

De longe, a maneira mais pura de obter os primeiros N elementos de uma matriz Swift é usar prefix(_ maxLength: Int):

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

Isso tem o benefício de ser seguro. Se a contagem para a qual você passar prefixfor maior que a contagem da matriz, ela retornará a matriz inteira.

NOTA: como indicado nos comentários, Array.prefixna verdade retorna um ArraySlice, não um Array. Na maioria dos casos, isso não deve fazer diferença, mas se você precisar atribuir o resultado a um Arraytipo ou passá-lo para um método que espera um Arrayparâmetro, será necessário forçar o resultado para um Arraytipo:let first5 = Array(someArray.prefix(5))

mluisbrown
fonte
41
+1 uma escolha de nome tão ruim, IMHO. A matriz possui dropFirste dropLast, portanto, pode ter takeFirste takeLast.
Mazyod 9/11/2015
10
Além disso, se você precisar first5ser uma matriz, basta escrever #let first5 = Array(someArray.prefix(5))
ULazdins 11/11
2
@mluisbrown Desculpe, não concordo com você :) No meu projeto video = video.prefix(5)no Xcode 7.2 resulta em erro de compilação Cannot assign value of type 'ArraySlice<Video>' to type '[Video]'
ULazdins
5
video = Array(video.prefix(5))
Bartłomiej Semańczyk 15/01
2
O @ onmyway133 prefixé possivelmente apenas o Swift 2.x (não me lembro se estava no 1.x), mas certamente existe em qualquer sistema operacional que suporte o Swift 2.x, que é o iOS 7 e superior. A disponibilidade do recurso Swift é determinada pelas versões do Swift, não pelas versões do iOS.
mluisbrown
99

Atualização: Agora existe a possibilidade de usar prefixpara obter os primeiros n elementos de uma matriz. Verifique a resposta de @ mluisbrown para obter uma explicação sobre como usar o prefixo.

Resposta original: Você pode fazer isso com muita facilidade sem filter, mapou reduceapenas retornando um intervalo de sua matriz:

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

var firstFive = wholeArray[0..<n] // 1,2,3,4,5
cristão
fonte
71
Se você deseja apenas os primeiros nitens de uma matriz Swift, você pode fazer o wholeArray.prefix(n)que tem o benefício adicional de estar seguro. Se nfor maior que o tamanho da matriz, prefixretornará toda a matriz.
mluisbrown
4
Ele irá falhar se o wholeArraynão tem mais elementos do quen
Jake Lin
@Crashalot Não tenho muita certeza, mas acho que na época em que escrevi minha resposta, não havia tal coisa prefix.
Christian
1
Use esse código para obter os 5 primeiros objetos ... Isso funciona perfeitamente [0,1,2,3,4,5] .enumerated (). FlatMap {$ 0 <5? $ 1: nil}
Manish Mahajan 10/04
64

Com o Swift 5, de acordo com suas necessidades, você pode escolher um dos 6 códigos seguintes do Playground para resolver seu problema.


# 1 Usando subscript(_:)subscrito

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

Complexidade: O (1) se a coleção estiver em conformidade RandomAccessCollection; caso contrário, O ( k ), onde k é o número de elementos a serem selecionados desde o início da coleção.

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

A Apple declara para prefix(_:):

Se o comprimento máximo exceder o número de elementos na coleção, o resultado conterá todos os elementos na coleção.


# 3 Usando o prefix(upTo:)método

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

A Apple declara para prefix(upTo:):

Usar o prefix(upTo:)método é equivalente a usar um intervalo semi-aberto parcial como o subscrito da coleção. A notação subscrita é preferida prefix(upTo:).


# 4 Usando o 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 Usando o removeSubrange(_:)método

Complexidade: O ( n ), em que n é o comprimento da coleção.

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

Complexidade: O (1) se a coleção estiver em conformidade RandomAccessCollection; caso contrário, O ( k ), onde k é o número de elementos a serem descartados.

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

SWIFT 4

Uma solução diferente:

Uma solução em linha fácil que não trava se o seu array for muito curto

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

Mas funciona bem com isso.

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

Normalmente, isso falharia se você fizesse isso:

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

[0,1,2,3,4,5].prefix(1000) // THIS DOESNT
David Rees
fonte
3
para swift3[0,1,2,3,4,5].enumerated().flatMap{ $0.offset < 1000 ? $0.element : nil }
StevenTsooo
1
Obrigado! Caso você queira atualizar, o flatMap agora é chamado compactMap no Swift 4 para compactação de array.
precisa saber é
14

Para obter os 5 primeiros elementos de uma matriz, tudo o que você precisa fazer é dividir a matriz em questão. Na Swift, você fazê-lo como este: array[0..<5].

Para tornar a escolha dos N primeiros elementos de uma matriz um pouco mais funcional e generalizável, você pode criar um método de extensão para fazê-lo. Por exemplo:

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

Alterei levemente a resposta de Markus para atualizá-la para a versão mais recente do Swift, pois vardentro da sua declaração de método não há mais suporte:

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

Swift 4

Para obter os primeiros N elementos de uma matriz Swift, você pode usar prefix(_ maxLength: Int):

Array(largeArray.prefix(5))
quemeful
fonte
1

Swift 4 com salvando tipos de array

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

Atualização para o swift 4:

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

Para o rápido 3:

[0,1,2,3,4,5].enumerated().flatMap{ $0 < 10000 ? $1 : nil }
mkkrolik
fonte
1
Solução ineficaz. 1) Você cria uma sequência adicional de comprimento de uma matriz. 2) Você itera através de todos os elementos.
Alexander Bekert 26/10
2
10000? O que é isso?
BangOperator
1

Plain & Simple

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

Para uma matriz de objetos, você pode criar uma extensão a partir de Sequência.

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
fonte