Using "Map" in Swift To Create Superset of Two Arrays

Actually you can do it using only map!

If the two sequences have the same size just enumerate and map:

let result = letterArray.enumerate().map { $0.element + String(numberArray[$0.index]) }

If you're not sure which one is larger and you wanna trim using the smaller just flatMap the undesired values away:

let result = letterArray.enumerate().flatMap {
    guard numberArray.count > $0.index else { return .None }
    return $0.element + String(numberArray[$0.index])
} as [String]

#1. Using zip(_:_:) to combine elements of an array of String with elements of an array of Int into a new array of String

With Swift 3, Swift Standard Library provides zip(_:_:) function. zip(_:_:) has the following declaration:

func zip<Sequence1, Sequence2>(_ sequence1: Sequence1, _ sequence2: Sequence2) -> Zip2Sequence<Sequence1, Sequence2> where Sequence1 : Sequence, Sequence2 : Sequence

Creates a sequence of pairs built out of two underlying sequences.


In order to get a new array from a Zip2Sequence instance, you can use Zip2Sequence's map(_:) method. The Playground code below that uses map(_:) combines your letter and number elements into a new array of String:

let letterArray = ["a", "b", "c", "d", "e"]
let numberArray = [1, 2, 3, 4, 5, 6, 7]

let zipSequence = zip(letterArray, numberArray)
let finalArray = zipSequence.map({ (tuple: (letter: String, number: Int)) -> String in
    return tuple.letter + String(tuple.number)
})

print(finalArray) // prints ["a1", "b2", "c3", "d4", "e5"]

You can refactor the previous code with a much concise style:

let letterArray = ["a", "b", "c", "d", "e"]
let numberArray = [1, 2, 3, 4, 5, 6, 7]

let finalArray = zip(letterArray, numberArray).map { $0.0 + String($0.1) }

print(finalArray) // prints ["a1", "b2", "c3", "d4", "e5"]

As an alternative to map(_:), you can use Zip2Sequence's reduce(_:_:) method:

let letterArray = ["a", "b", "c", "d", "e"]
let numberArray = [1, 2, 3, 4, 5, 6, 7]

let zipSequence = zip(letterArray, numberArray)
let finalArray = zipSequence.reduce([]) { (partialResult: [String], tuple: (letter: String, number: Int)) -> [String] in
    return partialResult + [tuple.letter + String(tuple.number)]
}

print(finalArray) // prints ["a1", "b2", "c3", "d4", "e5"]

#2. Using an Array extension custom method to combine elements of an array of String with elements of an array of Int into a new array of String

If you don't want to use zip(_:_:), you can create your own Array extension method in order to have the expected result. The Playground code below shows how to create it:

extension Array where Element == String {

    func mergeLettersWithNumbers(from numberArray: [Int]) -> [String] {
        var index = startIndex
        let iterator: AnyIterator<String> = AnyIterator {
            defer { index = self.index(index, offsetBy: 1) }
            guard index < self.endIndex, index < numberArray.endIndex else { return nil }
            return self[index] + String(numberArray[index])
        }
        return Array(iterator)
    }

}

let letterArray = ["a", "b", "c", "d", "e"]
let numberArray = [1, 2, 3, 4, 5, 6, 7]

let newArray = letterArray.mergeLettersWithNumbers(from: numberArray)
print(newArray) // prints ["a1", "b2", "c3", "d4", "e5"]

You can use zip(_:_:) before map:

let a = ["a", "b", "c", "d", "e"]
let b = [1, 2, 3, 4, 5]

let result = zip(a, b).map { $0 + String($1) }

print(result) // => ["a1", "b2", "c3", "d4", "e5"]

You can try this code here.

zip(_:_:) produces a custom Zip2Sequence, which has a special implmentation of the SequenceType protocol, so that it iterates pairs made from the two source collections.