Nova matriz do Swift do intervalo de índice

122

Como posso fazer algo assim? Pegue os primeiros n elementos de uma matriz:

newNumbers = numbers[0..n]

Atualmente, obtendo o seguinte erro:

error: could not find an overload for 'subscript' that accepts the supplied arguments

EDITAR:

Aqui está a função em que estou trabalhando.

func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
    var newNumbers = numbers[0...position]
    return newNumbers
}
Charlie Egan
fonte

Respostas:

179

Isso funciona para mim:

var test = [1, 2, 3]
var n = 2
var test2 = test[0..<n]

Seu problema pode estar na forma como você está declarando sua matriz para começar.

EDITAR:

Para consertar sua função, você deve converter seu Sliceem uma matriz:

func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
    var newNumbers = Array(numbers[0..<position])
    return newNumbers
}

// test
aFunction([1, 2, 3], 2) // returns [1, 2]
Cezary Wojcik
fonte
Adicionei um pouco mais de contexto à minha pergunta, estou trabalhando dentro de uma função. Isso funciona de forma independente, mas não dentro da função.
Charlie Egan
1
Encantador! Saúde - isso funciona. Aceitarei a resposta quando me permitir.
Charlie Egan
23
Ponto pedante, mas isso não é realmente lançando o Slicea um Array, mas sim a criação de uma nova matriz de uma fatia. Uma conversão usaria o asoperador: o numbers as Arrayque resultaria em um erro.
jb
A linguagem mudou, ele usa três reticências e não dois developer.apple.com/library/ios/documentation/General/Reference/...
Daniel Galasko
2
Os dois pontos ..mudaram para ..<; os três pontos (reticências) permaneceram os mesmos. Obrigado pelo lembrete; Eu atualizei a resposta.
Cezary Wojcik
100

# 1 Usando Arraysubscrito com intervalo

Com o Swift 5, quando você escreve…

let newNumbers = numbers[0...position]

newNumbersNão é do tipo, Array<Int>mas é do tipo ArraySlice<Int>. Isso porque Array's subscript(_:​)retorna um ArraySlice<Element>que, de acordo com a Apple, apresenta uma visão sobre o armazenamento de alguns matriz maior.

Além disso, o Swift também fornece Arrayum inicializador chamado init(_:​)que nos permite criar uma nova matriz a partir de um sequence(incluindo ArraySlice).

Portanto, você pode usar subscript(_:​)with init(_:​)para obter uma nova matriz dos primeiros n elementos de uma matriz:

let array = Array(10...14) // [10, 11, 12, 13, 14]
let arraySlice = array[0..<3] // using Range
//let arraySlice = array[0...2] // using ClosedRange also works
//let arraySlice = array[..<3] // using PartialRangeUpTo also works
//let arraySlice = array[...2] // using PartialRangeThrough also works
let newArray = Array(arraySlice)
print(newArray) // prints [10, 11, 12]

# 2 Usando Arrayo prefix(_:)método

Swift fornece um prefix(_:)método para tipos que estão em conformidade com o Collectionprotocolo (inclusive Array). prefix(_:)tem a seguinte declaração:

func prefix(_ maxLength: Int) -> ArraySlice<Element>

Retorna uma subsequência, até maxLength de comprimento, contendo os elementos iniciais.

A Apple também declara:

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

Portanto, como alternativa ao exemplo anterior, você pode usar o seguinte código para criar uma nova matriz a partir dos primeiros elementos de outra matriz:

let array = Array(10...14) // [10, 11, 12, 13, 14]
let arraySlice = array.prefix(3)
let newArray = Array(arraySlice)
print(newArray) // prints [10, 11, 12]
Imanou Petit
fonte
7
func subArray<T>(array: [T], range: NSRange) -> [T] {
  if range.location > array.count {
    return []
  }
  return Array(array[range.location..<min(range.length, array.count)])
}
Phil
fonte
adicione alguma descrição à resposta também.
Naman
Resposta muito boa. O que essencialmente faz é que ele lança um ArraySlice <T> para um Array. Pessoalmente, não incluiria tantas afirmações. Como normalmente quero que a fatia falhe se eu fornecer faixas falsas etc.
eonist
0

Mais uma variante usando extensione nome do argumentorange

Esta extensão usa RangeeClosedRange

extension Array {

    subscript (range r: Range<Int>) -> Array {
        return Array(self[r])
    }


    subscript (range r: ClosedRange<Int>) -> Array {
        return Array(self[r])
    }
}

Testes:

func testArraySubscriptRange() {
    //given
    let arr = ["1", "2", "3"]

    //when
    let result = arr[range: 1..<arr.count] as Array

    //then
    XCTAssertEqual(["2", "3"], result)
}

func testArraySubscriptClosedRange() {
    //given
    let arr = ["1", "2", "3"]

    //when
    let result = arr[range: 1...arr.count - 1] as Array

    //then
    XCTAssertEqual(["2", "3"], result)
}
yoAlex5
fonte
0

Matriz forma funcional:

   array.enumerated().filter { $0.offset < limit }.map { $0.element }

variou:

 array.enumerated().filter { $0.offset >= minLimit && $0.offset < maxLimit }.map { $0.element }

A vantagem desse método é que essa implementação é segura.

Vyacheslav
fonte