0

I am curious if there is any way in Swift to declare a multi-dimensional array that has a specific type(for this example we'll say Float) but isn't confined to a fixed number of dimensions(E.g., let arr: Array<Array<Float>>)?

I'd like to create a function that accepts a multi-dimensional array and currently the only way I'm aware of is:

func testFunction(arr: [Any]) {}

This is problematic though as it doesn't specify the actual scalar type of the array. As the type Any implies, this function can accept anything that is stuck inside of an Array. Any ideas?

1

3 Answers 3

1

Not with just an Array. Each array needs to know what type it contains. To contain an arbitrary number of dimensions, each array would need to be able to hold either a Float or an Array.

You could possible do something custom with an enum that has two cases.

enum MultidimensionalArray<Element> {
    case array([MultidimensionalArray<Element>])
    case values([Element])
}

but you'll probably have add a bunch more methods to it based on how you want to use ie.

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

1 Comment

I suppose it would also be possible to overload the function I'm describing with a separate case for each level of dimensions. E.g., func test(arr: Array<Float>) {} // single dimensions func test(arr: Array<Array<Float>>) {} // two dimensions func test(arr: Array<Array<Array<Float>>>) {} // three dimensions and so on. This is pretty messy though
1

How about generics

func testFunction<T>(arr: [T]) { }

T is a specific type and can be anything even

let foo = [[[[Float]]]]()
testFunction(arr: foo)

1 Comment

This will work, but it doesn't enforce a specific type on the scalars in the array. Which is really what this post is about. Although you are definitely on the right train of thought with using generics. I found a pretty slick way to get what I'm after which I've posted as an answer. Thanks for the input!
0

I found a way that makes it pretty simple to do what I'm after with some generic constraints and extensions.

protocol TypedNDArrayProtocol {}
// Make the type you are trying enforce conform to our protocol
extension Float: TypedNDArrayProtocol {}
// Now make Array conform to the same protocol while constraining
// it to only elements that *also* conform to this protocol
extension Array: TypedNDArrayProtocol where Element: TypedNDArrayProtocol {}

func testFunction(arr: Array<TypedNDArrayProtocol>) {}

This creates a sort of recursive conformance where the Array is allowed to accept either another Array, or a Float. If it is an Array, that Array can again only accept another Array or a Float and so on. This way you can use an arbitrary number of dimensions, but it must eventually terminate with a specific type; in this case a Float.

// This will work
testFunction(arr: [1.0, 2.0])

// This will also work
testFunction(arr: [[[3.0], [4.0]], [[5.0], [6.0]]])

// This will NOT work
testFunction(arr: [[[3], [4]], [[5], [6]]])

// Neither will this
testFunction(arr: [[["3"], ["4"]], [["5"], ["6"]]])

Comments

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.