Search code examples
arraysswift3subscript

ClosedRange and array subscripting in Swift 3


I'm converting my code to Swift 3 and have just 3 buildtime errors left, 2 of which have to do with my lack of understanding how ranges now work. For example, I have:

func shuffle( _ tenseArray: [ Tense ], ...

    var indices = [ Int ]()
    for tense in tenseArray {
        if let aRange = tenseRange[ tense ] { 
            indices.append( aRange )
        }
    }

Where Tense is an enum that looks something like:

 enum Tense: String {
    case IndicativePresent = "Indicative Present"
    case IndicativePreterite = "Indicative Preterite"
    case IndicativeImperfect = "Indicative Imperfect"
    ...

And tenseRange is defined as:

var tenseRange: [ Tense : ClosedRange<Int> ] = [:] // maps Tense enums to ranges of tense indices

and is populated like this:

tenseRange[ Tense.IndicativePresent ] = ( 11 ... 16 )
tenseRange[ Tense.IndicativePreterite ] = ( 17 ... 22 )
tenseRange[ Tense.IndicativeImperfect ] = ( 23 ... 28 )
...

For the line in func shuffle

indices.append( aRange )

I'm getting the error Cannot subscript a value of type '[Int]' with an index of type 'CountableRange'. I really would like to convert those ranges into ints for use in indices of an array as I was able to do previously in Swift, but I can't seem to figure out how. Any ideas?

Thanks in advance!


Solution

  • You declare your indices as an Array of Int, so you cannot use append(_:) for ClosedRange<Int>.

    So, I assume you want to append all values in the ClosedRange to indices.

    In such cases, you may need to use append(contentsOf:), not append(_:).

    Array

    ...

    func append(Element)

    Adds a new element at the end of the array.

    ...

    func append(contentsOf: C)

    Adds the elements of a collection to the end of the array.

    func append(contentsOf: S)

    Adds the elements of a sequence to the end of the array.

    Unfortunately, in Swift 3, CountableRange<T> is not a Collection nor a Sequence.

    But Swift 3 introduced an new Range family types, CountableClosedRange<T> and CountableRange<T>, which are both Collection. And the result type of closed range operator ... can be a CountableClosedRange<T> when placed in a specific context.

            indices.append(contentsOf: aRange.lowerBound...aRange.upperBound)
    

    Or else, you can declare your tenseRange's value as CountableClosedRange<Int>.

    var tenseRange: [ Tense : CountableClosedRange<Int> ] = [:]