In Swift, is there a way to to assign elements of array to multiple variables?

Viewed 845

I have a long array like this:

let array = [1, 2, 3]

and I want to assign the values of all elements to different variables like this:

var a, b, c:Int
[a, b, c] = array

I know it is possible with tuples, but I need to do it with array and without doing each variable individually.

2 Answers

In the list of patterns available, there is no "array pattern" or anything like that, so you can't pattern match on arrays. However, what you can do is:

let array = [1,2,3]
let (a, b, c) = (array[0], array[1], array[2])

This will throw an error at runtime if the array has less than 3 elements.

It's useful, but it's not built-in. And non-variadic generics make it a pain.

let (a, b, c) = [1, 2, 3].tuple3!
/// A workaround for not being able to extend tuples.
public struct Tuple<Elements> {
  public var elements: Elements

  public init(_ elements: Elements) {
    self.elements = elements
  }
}
public extension Tuple {
  // MARK: - 2-tuple

  /// Create a new tuple with one more element.
  static subscript<Element0, Element1, Element2>(
    tuple: Elements, element: Element2
  ) -> (Element0, Element1, Element2)
  where Elements == (Element0, Element1) {
    (tuple.0, tuple.1, element)
  }

  // MARK: - 3-tuple

  /// Create a new tuple with one more element.
  static subscript<Element0, Element1, Element2, Element3>(
    tuple: Elements, element: Element3
  ) -> (Element0, Element1, Element2, Element3)
  where Elements == (Element0, Element1, Element2) {
    (tuple.0, tuple.1, tuple.2, element)
  }
}
public extension Sequence {
  typealias Tuple2 = (Element, Element)
  typealias Tuple3 = (Element, Element, Element)
  typealias Tuple4 = (Element, Element, Element, Element)

  var tuple2: Tuple2? { makeTuple2()?.tuple }
  var tuple3: Tuple3? { makeTuple3()?.tuple }
  var tuple4: Tuple4? { makeTuple4()?.tuple }

  private func makeTuple2() -> (
    tuple: Tuple2,
    getNext: () -> Element?
  )? {
    var iterator = makeIterator()
    let getNext = { iterator.next() }

    guard
      let _0 = getNext(),
      let _1 = getNext()
    else { return nil }

    return ((_0, _1), getNext)
  }

  private func makeTuple3() -> (
    tuple: Tuple3,
    getNext: () -> Element?
  )? {
    guard
      let (tuple, getNext) = makeTuple2(),
      let element = getNext()
    else { return nil }

    return (Tuple[tuple, element], getNext)
  }

  private func makeTuple4() -> (
    tuple: Tuple4,
    getNext: () -> Element?
  )? {
    guard
      let (tuple, getNext) = makeTuple3(),
      let element = getNext()
    else { return nil }

    return (Tuple[tuple, element], getNext)
  }
}
Related