Mikhail
Mikhail

Reputation: 4311

Swift: iterate using Index and Element

I want to implement function in Swift similar to default find, but which accept comparator:

func find<C : CollectionType>(domain: C, comparator: (C.Generator.Element) -> Bool) -> C.Index? {
    for (index, element) in enumerate(domain) {
        if comparator(element) {
            return index
        }
    }

    return nil
}

The problem that enumerate returns tuple of type (Int, C.Generator.Element), while i need (C.Index, C.Generator.Element). I have searched much, but didn't find how to iterate using C.Index type.

Edit.

Sorry, it was a typo. I mean enumerate instead of generate

Upvotes: 2

Views: 211

Answers (2)

Airspeed Velocity
Airspeed Velocity

Reputation: 40973

The easiest solution is to use indices rather than enumerate, then use subscript to fetch the value:

func find<C : CollectionType>(domain: C, comparator: (C.Generator.Element) -> Bool) -> C.Index? {
    for index in indices(domain) {
        if comparator(domain[index]) {
            return index
        }
    }

    return nil
}

but I'm guessing you already knew that and wanted a solution that got you both the element and the index together without needing subscript. You could use Zip2 to do this:

func find<C : CollectionType>(domain: C, comparator: (C.Generator.Element) -> Bool) -> C.Index? {
    for (index, element) in Zip2(indices(domain), domain) {
        if comparator(element) {
            return index
        }
    }

    return nil
}

edit: as Rob points out below, this is guaranteed to work per the swift docs.

However this relies on something that makes me slightly uneasy, which is assuming that iterating over a collection via it's generator is guaranteed to return values in the same order as they are indexed. It would possibly be a slightly obnoxious thing for a collection to not do this (and since most collections use IndexingGenerator to serve up their generators, it's very likely to be the case). But I don't think it's documented as a guarantee so could be considered iffy.

Upvotes: 2

Rob Napier
Rob Napier

Reputation: 299703

As Airspeed Velocity notes, I assume you mean enumerate here rather than generate. The tool you want, however, is indices to get all the indices of the collection:

func find<C : CollectionType>(domain: C, comparator: (C.Generator.Element) -> Bool) -> C.Index? {
    for index in indices(domain) {
        if comparator(domain[index]) {
            return index
        }
    }    
    return nil
}

Upvotes: 2

Related Questions