How do I concatenate or merge arrays in Swift?
ArraysSwiftMergeArrays Problem Overview
If there are two arrays created in swift like this:
var a:[CGFloat] = [1, 2, 3]
var b:[CGFloat] = [4, 5, 6]
How can they be merged to [1, 2, 3, 4, 5, 6]
?
Arrays Solutions
Solution 1 - Arrays
You can concatenate the arrays with +
, building a new array
let c = a + b
print(c) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
or append one array to the other with +=
(or append
):
a += b
// Or:
a.append(contentsOf: b) // Swift 3
a.appendContentsOf(b) // Swift 2
a.extend(b) // Swift 1.2
print(a) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
Solution 2 - Arrays
With Swift 5, according to your needs, you may choose one of the six following ways to concatenate/merge two arrays.
Array
's +(_:_:)
generic operator
#1. Merge two arrays into a new array with Array
has a +(_:_:)
generic operator. +(_:_:)
has the following declaration:
>Creates a new collection by concatenating the elements of a collection and a sequence.
static func + <Other>(lhs: Array<Element>, rhs: Other) -> Array<Element> where Other : Sequence, Self.Element == Other.Element
The following Playground sample code shows how to merge two arrays of type [Int]
into a new array using +(_:_:)
generic operator:
let array1 = [1, 2, 3]
let array2 = [4, 5, 6]
let flattenArray = array1 + array2
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]
Array
's +=(_:_:)
generic operator
#2. Append the elements of an array into an existing array with Array
has a +=(_:_:)
generic operator. +=(_:_:)
has the following declaration:
>Appends the elements of a sequence to a range-replaceable collection.
static func += <Other>(lhs: inout Array<Element>, rhs: Other) where Other : Sequence, Self.Element == Other.Element
The following Playground sample code shows how to append the elements of an array of type [Int]
into an existing array using +=(_:_:)
generic operator:
var array1 = [1, 2, 3]
let array2 = [4, 5, 6]
array1 += array2
print(array1) // prints [1, 2, 3, 4, 5, 6]
Array
's append(contentsOf:)
method
#3. Append an array to another array with Swift Array
has an append(contentsOf:)
method. append(contentsOf:)
has the following declaration:
>Adds the elements of a sequence or collection to the end of this collection.
mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element
The following Playground sample code shows how to append an array to another array of type [Int]
using append(contentsOf:)
method:
var array1 = [1, 2, 3]
let array2 = [4, 5, 6]
array1.append(contentsOf: array2)
print(array1) // prints [1, 2, 3, 4, 5, 6]
Sequence
's flatMap(_:)
method
#4. Merge two arrays into a new array with Swift provides a flatMap(_:)
method for all types that conform to Sequence
protocol (including Array
). flatMap(_:)
has the following declaration:
>Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.
func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
The following Playground sample code shows how to merge two arrays of type [Int]
into a new array using flatMap(_:)
method:
let array1 = [1, 2, 3]
let array2 = [4, 5, 6]
let flattenArray = [array1, array2].flatMap({ (element: [Int]) -> [Int] in
return element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]
Sequence
's joined()
method and Array
's init(_:)
initializer
#5. Merge two arrays into a new array with Swift provides a joined()
method for all types that conform to Sequence
protocol (including Array
). joined()
has the following declaration:
> Returns the elements of this sequence of sequences, concatenated.
func joined() -> FlattenSequence<Self>
Besides, Swift Array
has a init(_:)
initializer. init(_:)
has the following declaration:
> Creates an array containing the elements of a sequence.
init<S>(_ s: S) where Element == S.Element, S : Sequence
Therefore, the following Playground sample code shows how to merge two arrays of type [Int]
into a new array using joined()
method and init(_:)
initializer:
let array1 = [1, 2, 3]
let array2 = [4, 5, 6]
let flattenCollection = [array1, array2].joined() // type: FlattenBidirectionalCollection<[Array<Int>]>
let flattenArray = Array(flattenCollection)
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]
Array
's reduce(_:_:)
method
#6. Merge two arrays into a new array with Swift Array
has a reduce(_:_:)
method. reduce(_:_:)
has the following declaration:
> Returns the result of combining the elements of the sequence using the given closure.
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
The following Playground code shows how to merge two arrays of type [Int]
into a new array using reduce(_:_:)
method:
let array1 = [1, 2, 3]
let array2 = [4, 5, 6]
let flattenArray = [array1, array2].reduce([], { (result: [Int], element: [Int]) -> [Int] in
return result + element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]
Solution 3 - Arrays
If you are not a big fan of operator overloading, or just more of a functional type:
// use flatMap
let result = [
["merge", "me"],
["We", "shall", "unite"],
["magic"]
].flatMap { $0 }
// Output: ["merge", "me", "We", "shall", "unite", "magic"]
// ... or reduce
[[1],[2],[3]].reduce([], +)
// Output: [1, 2, 3]
Solution 4 - Arrays
My favorite method since Swift 2.0 is flatten
var a:[CGFloat] = [1, 2, 3]
var b:[CGFloat] = [4, 5, 6]
let c = [a, b].flatten()
This will return FlattenBidirectionalCollection
so if you just want a CollectionType
this will be enough and you will have lazy evaluation for free. If you need exactly the Array you can do this:
let c = Array([a, b].flatten())
Solution 5 - Arrays
To complete the list of possible alternatives, reduce
could be used to implement the behavior of flatten:
var a = ["a", "b", "c"]
var b = ["d", "e", "f"]
let res = [a, b].reduce([],combine:+)
The best alternative (performance/memory-wise) among the ones presented is simply flatten
, that just wrap the original arrays lazily without creating a new array structure.
But notice that flatten does not return a LazyCollection
, so that lazy behavior will not be propagated to the next operation along the chain (map, flatMap, filter, etc...).
If lazyness makes sense in your particular case, just remember to prepend or append a .lazy
to flatten()
, for example, modifying Tomasz sample this way:
let c = [a, b].lazy.flatten()
Solution 6 - Arrays
Swift 4.X
easiest way I know is to just use the + sign
var Array1 = ["Item 1", "Item 2"]
var Array2 = ["Thing 1", "Thing 2"]
var Array3 = Array1 + Array2
// Array 3 will just be them combined :)
Solution 7 - Arrays
If you want the second array to be inserted after a particular index you can do this (as of Swift 2.2):
let index = 1
if 0 ... a.count ~= index {
a[index..<index] = b[0..<b.count]
}
print(a) // [1.0, 4.0, 5.0, 6.0, 2.0, 3.0]
Solution 8 - Arrays
Swift 3.0
You can create a new array by adding together two existing arrays with compatible types with the addition operator (+
). The new array's type is inferred from the type of the two array you add together,
let arr0 = Array(repeating: 1, count: 3) // [1, 1, 1]
let arr1 = Array(repeating: 2, count: 6)//[2, 2, 2, 2, 2, 2]
let arr2 = arr0 + arr1 //[1, 1, 1, 2, 2, 2, 2, 2, 2]
this is the right results of above codes.
Solution 9 - Arrays
var arrayOne = [1,2,3]
var arrayTwo = [4,5,6]
if you want result as : [1,2,3,[4,5,6]]
arrayOne.append(arrayTwo)
above code will convert arrayOne as a single element and add it to the end of arrayTwo.
if you want result as : [1, 2, 3, 4, 5, 6] then,
arrayOne.append(contentsOf: arrayTwo)
above code will add all the elements of arrayOne at the end of arrayTwo.
Thanks.
Solution 10 - Arrays
Here's the shortest way to merge two arrays.
var array1 = [1,2,3]
let array2 = [4,5,6]
Concatenate/merge them
array1 += array2
New value of array1 is [1,2,3,4,5,6]
Solution 11 - Arrays
Swift 5 Array Extension
extension Array where Element: Sequence {
func joined() -> Array<Element.Element> {
return self.reduce([], +)
}
}
Example:
let array = [[1,2,3], [4,5,6], [7,8,9]]
print(array.joined())
//result: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Solution 12 - Arrays
A much efficient way would be to use chain method defined in the Algorithms package made by Apple.
let numbers1 = [1, 2, 3, 4]
let numbers2 = [5, 6, 7, 8]
let allNumbers = chain(numbers1, numbers2)
for num in allNumbers {
print(num)
}
// for loop prints 1 to 8
It can also work with mixed Sequence types like Array of Integers and Range of Integers
let numbers = chain([10, 20, 30], 1...5)
// looping numbers will produce 10, 20, 30, 1, 2, 3, 4, 5
Similarly also works on String
let letters = chain("foo", "BAR")
// "fooBAR"
Chain is way more efficient compared to the +
operator or any other methods mentioned above because it does not create a new copy of array while concatenating.
It essentially iterates the first sequence and when it encounters endIndex in the first sequence it starts iterating the second sequence seamlessly.
Solution 13 - Arrays
Similarly, with dictionaries of arrays one can:
var dict1 = [String:[Int]]()
var dict2 = [String:[Int]]()
dict1["key"] = [1,2,3]
dict2["key"] = [4,5,6]
dict1["key"] = dict1["key"]! + dict2["key"]!
print(dict1["key"]!)
and you can iterate over dict1 and add dict2 if the "key" matches
Solution 14 - Arrays
So this problem really cries for flatMap
, no need to reimplement something by ourselfes or using reduce:
var a:[CGFloat] = [1, 2, 3]
var b:[CGFloat] = [4, 5, 6]
let merged = [a, b].flatMap { $0 }
That's it - have fun
Solution 15 - Arrays
Marge array that are different data types :
var arrayInt = [Int]()
arrayInt.append(6)
var testArray = ["a",true,3,"b"] as [Any]
testArray.append(someInt)
Output :
["a", true, 3, "b", "hi", 3, [6]]