Reputation: 713
Currently we iterate string as below:
let greeting = "Hello"
for (intIndex, char) in greeting.enumerated() {
let currentIndex = greeting.index(greeting.startIndex, offsetBy: intIndex)
let indexAfterCurrentIndex = greeting.index(after: currentIndex)
print(greeting[indexAfterCurrentIndex...])
}
I feel writing below code is redundant.
let currentIndex = greeting.index(greeting.startIndex, offsetBy: intIndex)
Is there other way to get directly "String.Index" while iterating?
Something like this
let greeting = "Hello"
for (stringIndex, char) in greeting.enumeratedXXX() {
let indexAfterCurrentIndex = greeting.index(after: stringIndex)
print(greeting[indexAfterCurrentIndex...])
}
Upvotes: 0
Views: 2010
Reputation: 866
func mergeAlternately (word1: String, word2: String){
var count = 0;
var result = "";
while (count < word1.count || count < word2.count ) {
let index = word1.index(word1.startIndex, offsetBy: count) // 0-based index, 2nd position for 'l'
let character = word1[index]
result += String(character);
print(result) // Output: "l"`enter code here`
count = count + 1
}
}
Upvotes: 0
Reputation: 540075
If you need the string indices then you can enumerate greeting.indices
:
let greeting = "Hello"
for index in greeting.indices {
// ...
}
If you need each character together with its index then you can enumerate the string and the indices in parallel:
let greeting = "Hello"
for (char, currentIndex) in zip(greeting, greeting.indices) {
let indexAfterCurrentIndex = greeting.index(after: currentIndex)
print(char, "-", greeting[indexAfterCurrentIndex...])
}
Output:
H - ello e - llo l - lo l - o o -
A simpler variant would be
let greeting = "Hello"
for (char, nextIndex) in zip(greeting, greeting.indices.dropFirst()) {
print(char, "-", greeting[nextIndex...])
}
which produces almost the same result, only without the last character/index pair:
H - ello e - llo l - lo l - o
Upvotes: 2
Reputation: 2932
There is no built-in functionality for this. You could wrap this in a custom iterator, but then you only encapsulate the same kind of computation in a different place, so that's not an answer :)
However, you can improve performance of your current code:
greeting.index(greeting.startIndex, offsetBy: intIndex)
startIndex
to the resulting index for every loop iteration. index(_:offsetBy:)
is really just another loop itself, where it +1
s each index. There's no O(1)
way to "compute" the index; it is found out by a loop in O(n)
So your own outer loop is linear with O(n)
for n
iterations, one for every character.
Then computing the index with an inner loop means there are 1+2+3+4+5+6+...n = (n^2 + n)/2
iterations, where n
is the intIndex
in this case.
That means the algorithm has a complexity of *handwaiving* roundabout O(n + n^2)
. The quadratic part is problematic!
You can get the complexity down to 2 operations per iteration, or O(2n)
. Just keep the previously computed index in memory and +1 yourself, avoiding a recomputation from scratch.
Here's the code:
let greeting = "Hello"
var index = greeting.startIndex
for char in greeting {
let indexAfterCurrentIndex = greeting.index(after: index)
print(greeting[indexAfterCurrentIndex...])
index = indexAfterCurrentIndex
}
Still not a simple and built-in solution, but you can just as well wrap this more efficient algorithm and off you go!
extension String {
func forEachCharacterWithIndex(iterator: (String.Index, Character) -> Void) {
var currIndex = self.startIndex
for char in self {
iterator(currIndex, char)
currIndex = self.index(after: currIndex)
}
}
}
let greeting = "Hello"
greeting.forEachCharacterWithIndex { (index, char) in
let indexAfterCurrentIndex = greeting.index(after: index)
print(greeting[indexAfterCurrentIndex...])
}
Upvotes: 3
Reputation: 55
Why not increment the currentIndex by 1 ?
let greeting = "Hello"
for (stringIndex, char) in greeting.enumerated() {
let currentIndex = stringIndex
let nextIndex = currentIndex + 1
print(nextIndex)
}
Upvotes: -1