Anna
Anna

Reputation: 571

How to concatenate an optional array to another array in Swift?

I know this sounds ridiculous but I am seriously confused now. Basically I have two vars, one is [Data] and one is Array<Data>?

I need to combine these two. I've tried do var1+var2, which is giving me errors say can't do binary operations on these two. So I googled, I can use append method, now there comes more questions:

  1. the append method is crossed out in autofill, so I am not sure if I should use it.
  2. Even if I try to use it (while it's being crossed out), it is still giving me errors

Here is the code and errors I get:

var a1:[Data] //a return value from other function
var a2:Array<Data>? //a parameter that's passed in

a1.append(contentsOf:a2) //Cannot use mutating member on immutable value: function call returns immutable value
a1+a2 //Binary operator '+' cannot be applied to operands of type 'Array<Data>' and 'Array<Data>?'

Both arrays can be empty, how can I concatenate these two arrays?

Upvotes: 0

Views: 1215

Answers (3)

Leo Dabus
Leo Dabus

Reputation: 236420

You can also extend RangeReplaceable Collection and implement a custom append method as well as addition and mutating addition operators as follow:

extension RangeReplaceableCollection {
    public mutating func append<S: Sequence>(contentsOf sequence: S?) where Element == S.Element {
        guard let sequence = sequence else { return }
        reserveCapacity(count + sequence.underestimatedCount)
        append(contentsOf: sequence)
    }
}

extension RangeReplaceableCollection {
    public static func += <S: Sequence>(lhs: inout Self, rhs: S?) where Element == S.Element {
        guard let rhs = rhs else { return }
        lhs.reserveCapacity(lhs.count + rhs.underestimatedCount)
        lhs.append(contentsOf: rhs)
    }
}

extension RangeReplaceableCollection {
    public static func + <S: Sequence>(lhs: Self, rhs: S?) -> Self where Element == S.Element {
        guard let rhs = rhs else { return lhs }
        var result = Self()
        result.reserveCapacity(lhs.count + rhs.underestimatedCount)
        result.append(contentsOf: lhs)
        result.append(contentsOf: rhs)
        return result
    }
}

Playground Testing

var a1 = "abc"
let a2: String? = "d"
let a3: String? = nil
let a4: [Character]? = ["e","f"]

a1 + a2 + a3 + a4  // "abcdef"

a1 + a2
print("a1:", a1)
a1 += a2
print("a1:", a1)
a1 + a3
print("a1:", a1)
a1 += a3
print("a1:", a1)
a1 + a4
print("a1:", a1)
a1 += a4
print("a1:", a1)

a1.append(contentsOf: ["e","f","g"])
print("a1:", a1)
a1.append(contentsOf: "hijkl")
print("a1:", a1)

Upvotes: 1

John Montgomery
John Montgomery

Reputation: 7096

Sulthan's answer is the quick solution, but if you do this a lot in your code, you can overload + to handle it for you automatically:

extension Array {
    static func + (lhs: [Element], rhs: [Element]?) -> [Element] {
        return lhs + (rhs ?? [])
    }
}

Upvotes: 1

Sulthan
Sulthan

Reputation: 130122

One of the arrays is optional. You have to handle the possible nil value somehow.

A simple solution using nil-coalescing:

let concatenated = var1 + (var2 ?? [])

or, slightly more complex:

var concatenated = var1

if let var2 = var2 {
   concatenated.append(var2)
}

There are other possible solutions, of course.

Upvotes: 2

Related Questions