0

I would like to use more functional programming in Swift. Some of the functions I write could work well on Arrays of various types. I don't want to rewrite the same function with different types (or typealiases.) The pattern how the function would work is often the same, just with different types. So, I tried something like this:

// Add indeces to an array of any type. I.e., returns an array of tuples of the array index and the original element.
func addIndeces<T: AnyObject>(toArray: Array<T>) -> Array<(index: Int, value: T)> {
    var arrIndex: [Int] = []
    for index in 0...toArray.count {
        arrIndex.append(index)
    }   
    return Array(Zip2(arrIndex, toArray))
}

When I call this function

// Note: reminderList is of type [Reminder]
let indexedReminderList = addIndeces(reminderList) as! [(index: Int, reminder: Reminder)]

I get a runtime error: "fatal error: can't unsafeBitCast between types of different sizes"

What am I doing wrong?

3
  • I've copied your code but I don't get a runtime error. Instead there is a compiletime error where it says that I should change as! to as. So can you explain why you cast your result at all? One side note: you can just return Array(Zip2(Array(0..<toArray.count), toArray)) Commented Jun 23, 2015 at 15:13
  • @Qbyte or even Array(zip(indices(toArray), toArray)) or (only works with integer-indexed collections) Array(enumerate(toArray)) Commented Jun 23, 2015 at 16:05
  • Thanks for the optimisations. I used them. However, the problem still exists. It needs to be 'as!' otherwise you get this error: 'Array<(index: Int, value: Reminder)>' is not convertible to '[(index: Int, reminder: Reminder)]'; did you mean to use 'as!' to force downcast? Commented Jun 23, 2015 at 17:09

3 Answers 3

2

The function you are writing already exists – kind of. enumerate "return a lazy SequenceType containing pairs (n, x), where n\ s are consecutive Int\ s starting at zero, and x\ s are the elements of base"

This means you can write your function as:

func addIndices<T>(toArray: [T]) -> [(index: Int, reminder: T)] {

    // if you want to label the tuple elements index: and reminder:,
    // you still have to use map:
    return map(enumerate(toArray)) {
        (index: $0, reminder: $1)
    }

}

Note, you don’t need to write T: AnyObject unless you specifically want to prevent this function from accepting anything other than arrays of classes (as that's what AnyObject is - the protocol that only classes, not structs or enums, conform to).

Note, enumerate only works for integer-indexed collections. To make it more general, you could write zip(indices(someCollection),someCollection)). indices returns a range of all the indices of any collection, so is equivalent to someCollection.startIndex..<someCollection.endIndex.

Sign up to request clarification or add additional context in comments.

Comments

1

You want to cast the tuple Array of type [(index: Int, value: T)] where T is of type Reminder to a tuple Array of type [(index: Int, reminder: Reminder)]. So you can see that the tuples have different element names (value and reminder) where both have different byte sizes - therefore the error.

So you should take the same element names for both tuples.

If you want to change the element names:

let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) }

Comments

0

The range 0...toArray.count consist all elements form 0 to the count of toArray, including the count value, and in your case arrIndex will always have one more element then toArray. Thats what is causing different size error. To fix it replace your range with this one 0..<toArray.count

4 Comments

I don't think that "size" is related to the size of the array rather than the actual byte-size of the type.
This is not fixing the problem.
@Qbyte Where exactly did it crash ? Just tried your code and its working like a charm
@Qbyte Sorry bro lately notice that you are not the OP

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.