3

What could be the swift equivalent of following python code ?

array =[ "a", "b", "c"]
print(array[1:])

( Above statement prints every element from first index upto end of array.
Output ['b', 'c'])

Edit
Is there a way where this could be done with out using array.count ? Since the array.count is redundant if I say want every element from second position

4
  • You could iterate over the array 'for string in array' this wouldn't use 'array.count' but what is against using it? Commented Apr 14, 2015 at 7:45
  • If expecting to drop only the first element, dropFirst(array) is usable. Commented Apr 14, 2015 at 8:05
  • @milo526 : I was expecting a more readable solution. Logically it should take only 1 argument in consideration(like python does). So I was wondering if there is some thing similar in swift. Considering the enhancements in swift 1.2, I think they might introduce this feature in future. Commented Apr 14, 2015 at 8:08
  • There's a library up on GitHub that lets you subscript an Array with a single argument using a .. operator, so array[1..] will give you all members of the array from the 1st index on up. It's not updated for Swift 1.2, but may work as is.... github.com/letvargo/LazyListSequence Commented Apr 14, 2015 at 19:54

3 Answers 3

9

With Swift 4, there is many ways to solve your problem. According to your needs, you may choose one of the six following patterns.


#1. Using Array dropFirst() method

let array = ["a", "b", "c"]
let arraySlice = array.dropFirst()
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]

#2. Using Array suffix(from:) method

let array = ["a", "b", "c"]
let arraySlice = array.suffix(from: 1)
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]

#3. Using Array suffix(_:) method

let array = ["a", "b", "c"]
let arraySlice = array.suffix(array.endIndex.advanced(by: -1))
// let arraySlice = array.suffix(array.count - 1) // also works
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]

#4. Using Array subscript(_:​) and CountableRange

let array = ["a", "b", "c"]
let range = array.startIndex.advanced(by: 1) ..< array.endIndex
// let range = 1 ..< array.count // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]

#5. Using Array subscript(_:​) and CountableClosedRange

let array = ["a", "b", "c"]
let range = 1 ... array.count - 1 // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]

#6. Using Array subscript(_:​) and CountablePartialRangeFrom

let array = ["a", "b", "c"]
let range = 1...
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
Sign up to request clarification or add additional context in comments.

Comments

5

You can get sub range of an swift array like that:

let array =[ "a", "b", "c"]
//be sure that your array.count has more than 1 item (in this case)
let subArray1 = array[1..<array.count]
print(subArray1)
//or
let subArray2 = array[1...array.count-1]
print(subArray2)

This is 2 notes from Swift Programming Language book

“Use .. to make a range that omits its upper value, and use ... to make a range that includes both values.”

And

“If you try to use subscript syntax to retrieve or set a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error. However, you can check that an index is valid before using it, by comparing it to the array’s count property. Except when count is 0 (meaning the array is empty), the largest valid index in an array will always be count - 1, because arrays are indexed from zero.”

Comments

3

You can achieve what you're looking for in the following way:

1. Create a custom struct to store a start and end index. If startIndex or endIndex is nil this will be taken to mean the range extends infinitely in that direction.

struct UnboundedRange<Index> {
    var startIndex, endIndex: Index?

    // Providing these initialisers prevents both `startIndex` and `endIndex` being `nil`.
    init(start: Index) {
        self.startIndex = start
    }

    init(end: Index) {
        self.endIndex = end
    }
}

2. Define operators to create an BoundedRange as having to use the initialisers will lead to some quite unsightly code, in my option.

postfix operator ... {}
prefix  operator ... {}

postfix func ... <Index> (startIndex: Index) -> UnboundedRange<Index> {
    return UnboundedRange(start: startIndex)
}

prefix func ... <Index> (endIndex: Index) -> UnboundedRange<Index> {
    return UnboundedRange(end: endIndex)
}

Some example usage:

1...  // An UnboundedRange<Int> that extends from 1 to infinity.
...10 // An UnboundedRange<Int> that extends from minus infinity to 10.

3. Extend the CollectionType so it can handle UnboundedRanges.

extension CollectionType {
    subscript(subrange: UnboundedRange<Index>) -> SubSequence {
        let start = subrange.startIndex ?? self.startIndex
        let end = subrange.endIndex?.advancedBy(1) ?? self.endIndex
        return self[start..<end]
    }
}

4. To use this in your given example:

let array = ["a", "b", "c"]

array[1...] // Returns ["b", "c"]
array[...1] // Returns ["a", "b"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.