Новий масив з індексу Range Swift


122

Як я можу зробити щось подібне? Візьміть перші n елементів з масиву:

newNumbers = numbers[0..n]

Наразі отримує таку помилку:

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

Редагувати:

Ось функція, над якою я працюю.

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

Відповіді:


179

Це працює для мене:

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

Ваша проблема може полягати в тому, як ви декларуєте свій масив для початку.

Редагувати:

Щоб виправити свою функцію, вам потрібно віддати її Sliceдо масиву:

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]

Я додаю трохи більше контексту до свого питання, я працюю всередині функції. Це працює незалежно, але не всередині функції.
Чарлі Еган

1
Прекрасна! Ура - це працює. Я прийму відповідь, коли це дозволить мені.
Чарлі Еган

23
Pedantic точка, але це на самому ділі не кидаючиSlice Аня Array, а створення нового масиву з шматочка. У ролях буде використаний asоператор: numbers as Arrayце призведе до помилки.
jb

Мова змінилася, вона використовує три еліпсиси, а не два developer.apple.com/library/ios/documentation/General/Reference/…
Даніель Галаско,

2
Дві крапки ..змінилися на ..<; три крапки (еліпсис) залишилися однаковими. Дякую за нагадування; Я оновив відповідь.
Цезарій Войцек

100

№1. Використання Arrayіндексу з діапазоном

З Swift 5, коли ви пишете ...

let newNumbers = numbers[0...position]

newNumbersНе типу, Array<Int>а типу ArraySlice<Int>. Це тому Array, що subscript(_:​)повертається, ArraySlice<Element>що, на думку Apple, представляє вид на зберігання якогось більшого масиву.

Крім того, Swift також пропонує Arrayініціалізатор, який називається, init(_:​)що дозволяє нам створити новий масив із sequence(у тому числі ArraySlice).

Таким чином, ви можете використовувати subscript(_:​)з init(_:​)для того , щоб отримати новий масив з перших п елементів масиву:

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. Використання Arrayросійського prefix(_:)методу

Swift пропонує prefix(_:)метод для типів, які відповідають Collectionпротоколу (у тому числі Array). prefix(_:)має таку заяву:

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

Повертає підряд, довжиною до maxLength, що містить початкові елементи.

Apple також заявляє:

Якщо максимальна довжина перевищує кількість елементів колекції, результат містить усі елементи колекції.

Тому в якості альтернативи попередньому прикладу ви можете використовувати наступний код для створення нового масиву з перших елементів іншого масиву:

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]

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

будь-ласка, додайте опис і до відповіді.
Наман

Дуже приємна відповідь. По суті, це те, що він передає ArraySlice <T> до масиву. Особисто я б не включив стільки тверджень. Як правило, я хочу, щоб фрагмент не
вдався,

0

Ще один варіант використання extensionі назви аргументуrange

Це розширення використовує RangeтаClosedRange

extension Array {

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


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

Тести:

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

0

Функціональний спосіб масиву:

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

діапазон:

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

Перевага цього методу полягає в тому, що така реалізація є безпечною.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.