Array
in Swift has several instance methods for excluding elements, such as dropFirst()
, dropLast()
, drop(while:)
, etc. What about drop(at:)
?
Note: I'd use remove(at:)
, but the array I'm working with is a let
constant.
Array
in Swift has several instance methods for excluding elements, such as dropFirst()
, dropLast()
, drop(while:)
, etc. What about drop(at:)
?
Note: I'd use remove(at:)
, but the array I'm working with is a let
constant.
Note: I'd use
remove(at:)
, but the array I'm working with is a constant.
I wouldn't let that stop you:
extension Array {
func drop(at:Int) -> [Element] {
var temp = self
temp.remove(at: at)
return temp
}
}
let numbers = [1, 2, 3, 4, 5]
print(numbers.drop(at: 2)) // [1, 2, 4, 5]
You can extend RangeReplaceableCollection
protocol instead of Array
type, this way you can use it on Strings as well:
extension RangeReplaceableCollection {
func drop(at offset: Int) -> SubSequence {
let index = self.index(startIndex, offsetBy: offset, limitedBy: endIndex) ?? endIndex
let next = self.index(index, offsetBy: 1, limitedBy: endIndex) ?? endIndex
return self[..<index] + self[next...]
}
}
var str = "Hello, playground"
str.drop(at: 5) // "Hello playground"
let numbers = [1, 2, 3, 4, 5]
print(numbers.drop(at: 2)) // "[1, 2, 4, 5]\n"
If you would like to accept also String.Index in your method:
extension RangeReplaceableCollection {
func drop(at index: Index) -> SubSequence {
let index = self.index(startIndex, offsetBy: distance(from: startIndex, to: index), limitedBy: endIndex) ?? endIndex
let next = self.index(index, offsetBy: 1, limitedBy: endIndex) ?? endIndex
return self[..<index] + self[next...]
}
}
var str = "Hello, playground"
str.drop(at: 0) // "ello, playground"
str.drop(at: str.startIndex) // "ello, playground"
The only thing I would add to your implementation is a guard statement with a useful error message:
extension Array {
func drop(at index: Int) -> ArraySlice<Element> {
guard indices.contains(index) else {
fatalError("Index out of range")
}
return self[0..<index] + self[(index+1)..<endIndex]
}
func drop(range: CountableRange<Int>) -> ArraySlice<Element> {
guard (indices.lowerBound, range.upperBound) <= (range.lowerBound, indices.upperBound) else {
fatalError("Range is out of the indices bounds")
}
return self[0..<range.lowerBound] + self[range.upperBound..<endIndex]
}
}
let a = [1,2,3]
a.drop(at: 3) //Fatal error: Index out of range
let b = [0,1,2,3,4,5]
b.drop(range: 1..<5) //[0, 5]
return self[0..<index] + self[index+1..<endIndex]
Ugly. Why not use the tools you're given?
extension Array {
func drop(at:Int) -> ArraySlice<Element> {
return prefix(upTo: at) + suffix(from: at+1)
}
}
let arr = [1,2,3,4,5]
let slice = arr.drop(at:2) // [1,2,4,5]
EDIT It seems Apple would prefer you to say (using partial ranges)
return self[..<at] + self[(at+1)...]
but personally I think that's uglier, and after all the methods I suggested are not deprecated or anything.
How about using a Swift extension to add drop(at:)
to the Array
structure?
extension Array {
func drop(at index: Int) -> ArraySlice<Element> {
precondition(indices.contains(index), "Index out of range")
return self[..<index] + self[(index+1)...]
}
}
It returns a slice of the original array without the element at the specified index.
let numbers = [1, 2, 3, 4, 5]
print(numbers.drop(at: 2))
// Prints "[1, 2, 4, 5]"
Note: You may also want to add drop(at:)
to ArraySlice
.