niranjanbajgai
niranjanbajgai

Reputation: 315

How can I convert an array to a tuple?

I just want to convert an array into a tuple in Swift; something like the following:

>>> myArray = [1,2,3,4,5]
>>> mytuple = tuple(myArray)
>>> mytuple
(1, 2, 3, 4, 5)

What's the easiest way of doing that?

(I only started learning Swift today, so I am very, very new).

Upvotes: 28

Views: 16172

Answers (5)

Dmitrii Guliagin
Dmitrii Guliagin

Reputation: 179

This my universal solution for copy array data to tuple. The only problem that I could not solve is to check the type of the element in the tuple and the element from the array.

/// Unsafe copy array to tuple
func unsafeCopyToTuple<ElementType, Tuple>(array: inout Array<ElementType>, to tuple: inout Tuple) {
    withUnsafeMutablePointer(to: &tuple) { pointer in
        let bound = pointer.withMemoryRebound(to: ElementType.self, capacity: array.count) { $0 }
        array.enumerated().forEach { (bound + $0.offset).pointee = $0.element }
    }
}

Upvotes: 2

钵钵鸡实力代购
钵钵鸡实力代购

Reputation: 1042

if what you want to do is extract multiple value from array at the same time, maybe the following code could help you

extension Array {
    func splat() -> (Element,Element) {
        return (self[0],self[1])
    }

    func splat() -> (Element,Element,Element) {
        return (self[0],self[1],self[2])
    }

    func splat() -> (Element,Element,Element,Element) {
        return (self[0],self[1],self[2],self[3])
    }

    func splat() -> (Element,Element,Element,Element,Element) {
        return (self[0],self[1],self[2],self[3],self[4])
    }
}

then you can use it like this

  let (first,_,third) = ( 0..<20 ).map { $0 }.splat()

you can even write a codegen to generate the extension code

Upvotes: 4

Menno
Menno

Reputation: 1292

Scared of unsafe pointers? Or need support for tuples with different types inside?

It can also be done like this:

public extension Array {

    public var tuple: Any? {
        switch count {
        case 0:
            return ()
        case 1:
            return (self[0])
        case 2:
            return (self[0], self[1])
        case 3:
            return (self[0], self[1], self[2])
        case 4:
            return (self[0], self[1], self[2], self[3])
        case 5:
            return (self[0], self[1], self[2], self[3], self[4])
        default:
            return nil
     }
 }

Because typing this out can be a little error prone, it's a good idea to write tests for this that make sure the right tuple is returned.

I've used this approach in ArrayPlusTuple.

So instead of writing this functionality yourself you could just add pod 'ArrayPlusTuple' to your pod file and get this tested functionality for free.

Upvotes: 2

Mazyod
Mazyod

Reputation: 22559

It's actually quite possible, if you are willing to do some low level magic. I don't think it works if the tuple has a collection type, though. This is mainly for interacting with C libraries.

typealias TupleType = (UInt8, UInt8, UInt8)

var array = [2, 3, 4] as [UInt8]
var tuple = UnsafeMutablePointer<StepsType>(malloc(UInt(sizeof(TupleType))))
memcpy(tuple, array, UInt(array.count))

More of this stuff can be found here: https://codereview.stackexchange.com/questions/84476/array-to-tuple-in-swift/84528#84528


Because 70% of us are highly visual beings:

enter image description here

Upvotes: 26

jtbandes
jtbandes

Reputation: 118671

You can't do this because the size of a tuple is part of its type, and this isn't true for an array. If you know the array's length, you can just do let myTuple = (myArray[0], myArray[1], ...). Or you can build your architecture around tuples from the beginning. What are you trying to do?

This is a common problem which occurs in lots of other languages. See How do I convert a list to a tuple in Haskell?

Upvotes: 16

Related Questions