Reputation: 5153
How can I do something like this? Take the first n elements from an array:
newNumbers = numbers[0..n]
Currently getting the following error:
error: could not find an overload for 'subscript' that accepts the supplied arguments
EDIT:
Here is the function that I'm working in.
func aFunction(numbers: Array<Int>, position: Int) -> Array<Int> {
var newNumbers = numbers[0...position]
return newNumbers
}
Upvotes: 168
Views: 165925
Reputation: 11636
I did appreciate Imanou Petit post.
Just to be complete for others using SUFFIX:
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]
let arraySlice2 = array.suffix(from: 3)
let newArray2 = Array(arraySlice2)
print(newArray2) // prints [13, 14]
Upvotes: 0
Reputation: 345
extension Array where Element : Equatable {
public subscript(safe bounds: Range<Int>) -> ArraySlice<Element> {
if bounds.lowerBound > count { return [] }
let lower = Swift.max(0, bounds.lowerBound)
let upper = Swift.max(0, Swift.min(count, bounds.upperBound))
return self[lower..<upper]
}
public subscript(safe lower: Int?, _ upper: Int?) -> ArraySlice<Element> {
let lower = lower ?? 0
let upper = upper ?? count
if lower > upper { return [] }
return self[safe: lower..<upper]
}
}
returns a copy of this range clamped to the given limiting range.
var arr = [1, 2, 3]
arr[safe: 0..<1] // returns [1] assert(arr[safe: 0..<1] == [1])
arr[safe: 2..<100] // returns [3] assert(arr[safe: 2..<100] == [3])
arr[safe: -100..<0] // returns [] assert(arr[safe: -100..<0] == [])
arr[safe: 0, 1] // returns [1] assert(arr[safe: 0, 1] == [1])
arr[safe: 2, 100] // returns [3] assert(arr[safe: 2, 100] == [3])
arr[safe: -100, 0] // returns [] assert(arr[safe: -100, 0] == [])
Upvotes: 15
Reputation: 27211
Array functional way:
array.enumerated().filter { $0.offset < limit }.map { $0.element }
ranged:
array.enumerated().filter { $0.offset >= minLimit && $0.offset < maxLimit }.map { $0.element }
The advantage of this method is such implementation is safe.
Upvotes: 4
Reputation: 34175
One more variant using extension
and argument name range
This extension uses Range
and ClosedRange
extension Array {
subscript (range r: Range<Int>) -> Array {
return Array(self[r])
}
subscript (range r: ClosedRange<Int>) -> Array {
return Array(self[r])
}
}
Tests:
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)
}
Upvotes: 0
Reputation: 92409
Array
subscript with rangeWith Swift 5, when you write…
let newNumbers = numbers[0...position]
… newNumbers
is not of type Array<Int>
but is of type ArraySlice<Int>
. That's because Array
's subscript(_:)
returns an ArraySlice<Element>
that, according to Apple, presents a view onto the storage of some larger array.
Besides, Swift also provides Array
an initializer called init(_:)
that allows us to create a new array from a sequence
(including ArraySlice
).
Therefore, you can use subscript(_:)
with init(_:)
in order to get a new array from the first n elements of an array:
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]
Array
's prefix(_:)
methodSwift provides a prefix(_:)
method for types that conform to Collection
protocol (including Array
). prefix(_:)
has the following declaration:
func prefix(_ maxLength: Int) -> ArraySlice<Element>
Returns a subsequence, up to maxLength in length, containing the initial elements.
Apple also states:
If the maximum length exceeds the number of elements in the collection, the result contains all the elements in the collection.
Therefore, as an alternative to the previous example, you can use the following code in order to create a new array from the first elements of another array:
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]
Upvotes: 153
Reputation: 21845
This works for me:
var test = [1, 2, 3]
var n = 2
var test2 = test[0..<n]
Your issue could be with how you're declaring your array to begin with.
EDIT:
To fix your function, you have to cast your Slice
to an array:
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]
Upvotes: 227