Using Maps in Swift to Create a Superset of Two Arrays

Let's say I have two arrays:

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

I want to combine two arrays to get output

 ["a1", "b2", "c3", "d4", "e5"] 

How can i do this?

+8
source share
3 answers

You can use zip(_:_:) in front of the 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(_:_:) creates a custom Zip2Sequence that has a special implementation of the SequenceType protocol, so it iterates through pairs created from two source collections.

+21
source

In fact, you can do this using only map !

If two sequences have the same size, only enumerate and map :

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

If you are not sure which one is larger, and you want to crop using smaller, flatMap smaller unwanted values:

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

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

With Swift 3, the standard Swift library provides a zip(_:_:) function zip(_:_:) . 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 constructed from two base sequences.


To get a new array from an instance of Zip2Sequence , you can use the Zip2Sequence map(_:) method. Below is the code below: map(_:) combines your letter and number elements into a new String array:

 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 reorganize the previous code with a very 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 the Zip2Sequence 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 the native Array extension method to combine the elements of the String array with the elements of the Int array into a new String array

If you do not want to use zip(_:_:) , you can create your own Array extension method to get the expected result. Below is the code for the playground:

 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"] 
+1
source

All Articles