2

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

1
  • 2
    you mean enumerate not generate, right? Commented Dec 29, 2014 at 20:10

2 Answers 2

2

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
}
Sign up to request clarification or add additional context in comments.

Comments

2

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.

4 Comments

I believe this is documented adequately in the definition of CollectionType: The sequence view of the elements is identical to the collection view. In other words, the following code binds the same series of values to x as does for x in self {}:: /// for i in startIndex..<endIndex { /// let x = self[i] /// }
aha you're right, in which case I retract my unease and decide I like this solution :)
Glad you used the moment to teach Zip2. So powerful, so little-explored.
what do you know, two Zip2 answers in one day

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.