Search code examples
swift3flatmap

Keeping an index with flatMap in Swift


This is a follow-up to this question:

flatMap and `Ambiguous reference to member` error

There I am using the following code to convert an array of Records to an array of Persons:

let records = // load file from bundle
let persons = records.flatMap(Person.init)

Since this conversion can take some time for big files, I would like to monitor an index to feed into a progress indicator.

Is this possible with this flatMap construction? One possibility I thought of would be to send a notification in the init function, but I am thinking counting the records is also possible from within flatMap ?


Solution

  • Yup! Use enumerated().

    let records = // load file from bundle
    let persons = records.enumerated().flatMap { offset, record in
        print(offset)
        return Person(record)
    }
    

    Just note that what you get is an offset (always counting up from 0). As the documentation clarifies:

    When you enumerate a collection, the integer part of each pair is a counter for the enumeration, but is not necessarily the index of the paired value. These counters can be used as indices only in instances of zero-based, integer-indexed collections, such as Array and ContiguousArray. For other collections the counters may be out of range or of the wrong type to use as an index. To iterate over the elements of a collection with its indices, use the zip(_:_:) function.

    If you want values that you can reliably use indices, use zip, as they suggest:

    let a = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
    let slice = a.dropFirst(3) // Indices start at 3
    
    for (index, element) in zip(slice.indices, slice) {
      print(slice[index], element) // The index is always valid for subscripting back into the collection
    }