Reputation: 2457
Example:
let a = [a1, a2, a3]
let b = [b1, b2]
let c = [c1, c2, c3, c4]
I need the following result:
[a1, b1, c1, a2, b2, c2, a3, c3, c4]
a1, b1, ... - any objects of the same type
My current solution is to create mutable copies of these arrays and call popFirst
sequentially on each array in the specified order until all the arrays become empty.
But is it possible to solve this task by using inner Swift features without of iterating manually? For example like the following code:
[a, b, c].map { ... }.filter { ... }.reduce ...
Upvotes: 1
Views: 2506
Reputation: 51872
Here is a solution using a basic for
loop but it is flexible in the number of arrays you can merge
func merge<T>(_ arrays: [T]...) -> [T] {
guard let longest = arrays.max(by: { $0.count < $1.count })?.count else { return [] }
var result = [T]()
for index in 0..<longest {
for array in arrays {
guard index < array.count else { continue }
result.append(array[index])
}
}
return result
}
Example from question
print(merge(a, b, c))
["a1", "b1", "c1", "a2", "b2", "c2", "a3", "c3", "c4"]
Upvotes: 2
Reputation: 270860
Think of this as "transposing" the 2D array [a, b, c]
, except when there isn't an element, you just ignore it and move on. This reminds me of this question of mine, except that you want the inner arrays to have different sizes.
We can modify Alexander's answer there to suit your needs by finding the inner array with the largest count
, and use that instead of the first inner array. We also change the outer map
to flatMap
since you want it flattened.
We also introduce a safe:
subscript, so that compactMap
can be used to ignore those "missing" elements.
extension Collection where Self.Element: RandomAccessCollection {
func transposed() -> [Self.Element.Element] {
guard let rowWithMaxElems = self.max(by: { $0.count < $1.count }) else { return [] }
return rowWithMaxElems.indices.flatMap { index in
self.compactMap { $0[safe: index] }
}
}
}
extension RandomAccessCollection {
subscript(safe index: Index) -> Element? {
get {
indices.contains(index) ? self[index] : nil
}
}
}
let a = [1, 2, 3]
let b = [4, 5]
let c = [6, 7, 8, 9]
let result = [a, b, c].transposed()
print(result)
Upvotes: 1
Reputation: 18904
You can do by this
let a = ["a1", "a2", "a3"]
let b = ["b1", "b2"]
let c = ["c1", "c2", "c3", "c4"]
let initArr = [a,b,c]
let maxCount = initArr.max(by: {$0.count < $1.count})?.count ?? 0
let newArr: [String] = (0..<maxCount).flatMap { (index) -> [String]in
var arr: [String] = []
_ = initArr.indices.map { (number)in
if index < initArr[number].count {
arr.append(initArr[number][index])
}
}
return arr
}
print(newArr) // ["a1", "b1", "c1", "a2", "b2", "c2", "a3", "c3", "c4"]
Upvotes: -1
Reputation: 10092
Try this -
let a = ["a1", "a2", "a3"]
let b = ["b1", "b2"]
let c = ["c1", "c2", "c3", "c4"]
var d: [String] = []
let count = max(a.count, b.count, c.count)
for i in 0..<count {
if i < a.count { d.append(a[i]) }
if i < b.count { d.append(b[i]) }
if i < c.count { d.append(c[i]) }
}
print(d)
Output -
["a1", "b1", "c1", "a2", "b2", "c2", "a3", "c3", "c4"]
Upvotes: 0