Reputation: 432
There is an array
var sampleArray = ["1","2","3","4","5","6","7","8","9","10"]
there are two elements "header
" and "footer
"
I want to add these two elements such way that after every 3rd index of original array these two are to be appended
Expected Output
sampleArray = ["1","2","3", "header","footer" ,"4","5","6","header","footer""7","8","9""header","footer",10]
I google through the same of the build in methods provided , I found below
insert(_:at:)
But its not serving my purpose, It looks an obvious problem, Is there anybody who created the function like this?
Upvotes: 1
Views: 1254
Reputation: 236458
The issue is that you are invalidating the indices of your collection when inserting new elements. From the docs
Calling this method may invalidate any existing indices for use with this collection.
The most simple solution when you need to insert or remove multiple elements is to iterate your collection indices in reverse order:
var sampleArray = ["1","2","3","4","5","6","7","8","9","10"]
var insertions = ["header", "footer"]
for index in sampleArray.indices.dropFirst().reversed() where index.isMultiple(of: 3) {
sampleArray.insert(contentsOf: insertions, at: index)
}
sampleArray // ["1", "2", "3", "header", "footer", "4", "5", "6", "header", "footer", "7", "8", "9", "header", "footer", "10"]
If you would like to implement your own insert methods:
extension RangeReplaceableCollection {
mutating func insert<C>(contentsOf newElements: C, every nth: Int) where C : Collection, Self.Element == C.Element, Index == Int {
for index in indices.dropFirst().reversed() where index.isMultiple(of: nth) {
insert(contentsOf: newElements, at: index)
}
}
mutating func insert(_ newElement: Element, every nth: Int) where Index == Int {
for index in indices.dropFirst().reversed() where index.isMultiple(of: nth) {
insert(newElement, at: index)
}
}
}
Usage:
sampleArray.insert(contentsOf: insertions, every: 3)
// sampleArray.insert("header", every: 3)
Upvotes: 1
Reputation: 272905
You can't just insert into the indices 3, 6, 9 etc, in that order, because after inserting at index 3, the next index to insert at changes (increases by the number of elements you inserted). The third time you insert, it's been shifted by twice the number of elements you inserted, and so on. If you take this into account, it's quite simple:
var sampleArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
let sectionLength = 3
let separator = ["header", "footer"]
for (count, i) in stride(from: sectionLength, to: sampleArray.endIndex, by: sectionLength).enumerated() {
sampleArray.insert(contentsOf: separator, at: i + count * separator.count)
}
Alternative solution that creates a new array:
let result = sampleArray.enumerated().flatMap { index, element in
index % 3 == 2 ? [element] + separator : [element]
}
The idea here is to flatMap
certain elements to that element plus the separator, and other elements to themselves. separator
should be added after 3
, 6
and 9
, which are at indices 2, 5, and 8 respectively. Their indices are all one less than a multiple of 3, hence index % 3 == 2
.
Upvotes: 1
Reputation: 401
Use new array to proper combine
var result: [String] = []
for index in 0..< sampleArray.count {
result.append(sample[index])
if (index+1) % 3 == 0 {
result.append("header")
result.append("footer")
}
}
Upvotes: 1