Nowa tablica z Index Range Swift

123

Jak mogę zrobić coś takiego? Weź pierwsze n elementów z tablicy:

newNumbers = numbers[0..n]

Obecnie jest wyświetlany następujący błąd:

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

EDYTOWAĆ:

Oto funkcja, w której pracuję.

func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
    var newNumbers = numbers[0...position]
    return newNumbers
}
Charlie Egan
źródło

Odpowiedzi:

182

To działa dla mnie:

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

Twój problem może być związany z tym, jak deklarujesz swoją tablicę na początku.

EDYTOWAĆ:

Aby naprawić swoją funkcję, musisz rzutować Sliceją na tablicę:

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 Wójcik
źródło
Dodałem trochę więcej kontekstu do mojego pytania, pracuję wewnątrz funkcji. Działa to niezależnie, ale nie wewnątrz funkcji.
Charlie Egan
1
Śliczny! Pozdrawiam - to działa. Przyjmuję odpowiedź, kiedy mi na to pozwoli.
Charlie Egan
23
Punkt pedantyczny, ale tak naprawdę nie jest to rzutowanie na Slicean Array, ale raczej tworzenie nowej tablicy z wycinka. Rzutowanie użyłoby asoperatora: numbers as Arrayco spowodowałoby błąd.
jb
Język się zmienił, używa trzech wielokropków, a nie dwóch developer.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko
2
Dwie kropki ..zmieniły się na ..<; trzy kropki (wielokropek) pozostały takie same. Dziękuję za przypomnienie; Zaktualizowałem odpowiedź.
Cezary Wójcik
100

# 1. Używanie Arrayindeksu dolnego z zakresem

Dzięki Swift 5, kiedy piszesz…

let newNumbers = numbers[0...position]

newNumbersNie jest typu, Array<Int>ale jest typu ArraySlice<Int>. Dzieje się tak dlatego Array, że subscript(_:​)zwraca wartość, ArraySlice<Element>która według Apple przedstawia widok na przechowywanie większej tablicy.

Poza tym Swift zapewnia Arrayrównież inicjator o nazwie, init(_:​)który pozwala nam utworzyć nową tablicę z sequence(w tym ArraySlice).

Dlatego możesz użyć subscript(_:​)with init(_:​), aby uzyskać nową tablicę z pierwszych n elementów tablicy:

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. Korzystanie Arrayz prefix(_:)metody

Swift zapewnia prefix(_:)metodę dla typów zgodnych z Collectionprotokołem (w tym Array). prefix(_:)posiada następującą deklarację:

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

Zwraca podsekwencję o maksymalnej długości maxLength, zawierającą elementy początkowe.

Apple stwierdza również:

Jeśli maksymalna długość przekracza liczbę elementów w kolekcji, wynik zawiera wszystkie elementy w kolekcji.

Dlatego, jako alternatywa dla poprzedniego przykładu, możesz użyć poniższego kodu, aby utworzyć nową tablicę z pierwszych elementów innej tablicy:

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
źródło
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
źródło
proszę również dodać opis do odpowiedzi.
Naman
Bardzo ładna odpowiedź. Zasadniczo robi to, że rzuca ArraySlice <T> na Array. Osobiście nie zamieściłbym tylu twierdzeń. Ponieważ zwykle chcę, aby wycinek się nie
udał,
0

Jeszcze jeden wariant z użyciem extensioni nazwą argumenturange

To rozszerzenie używa RangeiClosedRange

extension Array {

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


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

Testy:

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
źródło
0

Funkcjonalny sposób tablicy:

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

zasięg:

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

Zaletą tej metody jest to, że taka realizacja jest bezpieczna.

Wiaczesław
źródło