Новый массив из диапазона индексов Swift

123

Как я могу сделать что-то подобное? Возьмите первые 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
}
Чарли Иган
источник

Ответы:

182

Это работает для меня:

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
Две точки ..изменились на ..<; три точки (многоточие) остались прежними. Тем не менее, спасибо за напоминание; Я обновил ответ.
Cezary Wojcik
100

# 1. Использование Arrayиндекса с диапазоном

В Swift 5, когда вы пишете…

let newNumbers = numbers[0...position]

newNumbersНе тип, Array<Int>а тип ArraySlice<Int>. Это потому , что Array«S subscript(_:​)возвращаетArraySlice<Element> который, согласно Apple, представляет собой представление о хранилище некоторого большего массива.

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

Следовательно, вы можете использовать subscript(_:​)with init(_:​), чтобы получить новый массив из первых n элементов массива:

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«S 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> в массив. Лично я бы не стал включать так много утверждений. Как я обычно хочу кусочек , чтобы потерпеть неудачу , если я обеспечиваю ложные диапазоны и т.д.
eonist
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)
}
yoAlex5
источник
0

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

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

варьировались:

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

Преимущество этого метода в том, что такая реализация безопасна.

Вячеслав
источник