Nueva matriz de Index Range Swift

122

¿Cómo puedo hacer algo como esto? Tome los primeros n elementos de una matriz:

newNumbers = numbers[0..n]

Recibiendo actualmente el siguiente error:

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

EDITAR:

Aquí está la función en la que estoy trabajando.

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

Respuestas:

181

Esto funciona para mi:

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

Su problema podría ser cómo está declarando su matriz para empezar.

EDITAR:

Para arreglar su función, debe convertir su Sliceen una 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
fuente
Agregué un poco más de contexto a mi pregunta, estoy trabajando dentro de una función. Esto funciona de forma independiente, pero no dentro de la función.
Charlie Egan
1
¡Encantador! Saludos, eso funciona. Aceptaré la respuesta cuando me lo permita.
Charlie Egan
23
Punto pedante, pero esto no es realmente echando la Slicede una Array, sino más bien crear una nueva matriz de una rebanada. Un elenco usaría el asoperador: numbers as Arraylo que resultaría en un error.
jb
El idioma ha cambiado, utiliza tres puntos suspensivos y no dos developer.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko
2
Los dos puntos ..cambiaron a ..<; los tres puntos (puntos suspensivos) se han mantenido igual. De todas maneras, gracias por el recordatorio; Actualicé la respuesta.
Cezary Wojcik
100

# 1. Usando Arraysubíndice con rango

Con Swift 5, cuando escribes ...

let newNumbers = numbers[0...position]

... newNumbers No es de tipo Array<Int>sino de tipo ArraySlice<Int>. Eso es porque Array's subscript(_:​)devuelve una ArraySlice<Element>que, según Apple, presenta una visión sobre el almacenamiento de cierta matriz más grande.

Además, Swift también proporciona Arrayun inicializador llamado init(_:​)que nos permite crear una nueva matriz a partir de un sequence(incluido ArraySlice).

Por lo tanto, puede usar subscript(_:​)coninit(_:​) para obtener una nueva matriz a partir de los primeros n elementos de una 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 Arrayel prefix(_:)método de

Swift proporciona un prefix(_:)método para tipos que se ajustan al Collectionprotocolo (incluido Array). prefix(_:)tiene la siguiente declaración:

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

Devuelve una subsecuencia, hasta maxLength de longitud, que contiene los elementos iniciales.

Apple también afirma:

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

Por lo tanto, como alternativa al ejemplo anterior, puede utilizar el siguiente código para crear una nueva matriz a partir de los primeros elementos de otra 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
fuente
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
fuente
Por favor, agregue también una descripción a la respuesta.
Naman
Muy buena respuesta. Lo que esencialmente hace es que lanza un ArraySlice <T> a un Array. Personalmente no incluiría tantas afirmaciones. Como suelo quiero rebanada a fallar si proporciono falsos rangos etc.
eonist
0

Una variante más usando un extensionnombre de argumentorange

Esta extensión usa RangeyClosedRange

extension Array {

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


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

Pruebas:

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

Manera funcional de la matriz:

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

rango:

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

La ventaja de este método es que su implementación es segura.

Vyacheslav
fuente