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

Kaunteya
  • 3,107
  • 1
  • 35
  • 66
  • You could iterate over the array 'for string in array' this wouldn't use 'array.count' but what is against using it? – milo526 Apr 14 '15 at 07:45
  • If expecting to drop only the first element, `dropFirst(array)` is usable. – findall Apr 14 '15 at 08: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. – Kaunteya Apr 14 '15 at 08: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.... https://github.com/letvargo/LazyListSequence – Aaron Rasmussen Apr 14 '15 at 19:54

3 Answers3

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"]
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
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.”

Duyen-Hoa
  • 15,384
  • 5
  • 35
  • 44
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"]
ABakerSmith
  • 22,759
  • 9
  • 68
  • 78