Reputation: 7910
I'm trying to find out how many letters 2 words (which are known to have the same length and to be in roman characters only) have in common. To do so, I have the following code
var sameplace = 0
for n in 0..<(word1.utf16Count){
if word1[n] == word2[n]{
sameplace += 1
}
}
However, I get an error when trying to index the strings with n
, which is an Int
. The error is, specifically, 'Int' is not convertible to 'String.Index'
.
Is there a way to index a string with an int, without having to convert it to an NSString
every time first? Can I make the loop generate n as a String.Index
instead of an Int
? What's the most "swiftic" way to do this?
Upvotes: 2
Views: 776
Reputation: 539685
A possible solution which does even work with all kinds of Unicode characters, grapheme clusters etc:
let word1 = "😄abcd🇩🇪"
let word2 = "😄axcy🇩🇪"
var sameplace = 0
for (c1, c2) in Zip2(word1, word2) {
if c1 == c2 {
sameplace++
}
}
println(sameplace) // 4
A Swift String
is also a Sequence
of its characters, and
Zip2
returns a sequence that iterates over the two given sequences in parallel.
Upvotes: 4
Reputation: 2130
So, these other answers work, too, but there is a way to do this which gets you pretty close to the way you want to do it:
var sameplace = 0
for n in 0..<(word1.utf16Count) {
if Array(word1)[n] == Array(word2)[n] {
sameplace += 1
}
}
Upvotes: 0
Reputation: 94683
If you really need to access a character at a specific index, you can use the advance
function with the startIndex
of the string:
var sameplace = 0
for n in 0..<(word1.utf16Count){
if word1[advance(word1.startIndex, n)] == word2[advance(word2.startIndex, n)]{
sameplace += 1
}
}
However, this is terribly inefficient because it iterates to n for every iteration through the for loop. It is also not ideal to assume the utf16 count is correct.
Instead, you can iterate the String.Index
s more manually:
var sameplace = 0
var index1 = word1.startIndex
var index2 = word2.startIndex
do {
if word1[index1] == word2[index2]{
sameplace += 1
}
index1 = index1.successor()
index2 = index2.successor()
}
while(index1 != word1.endIndex && index2 != word2.endIndex);
You could also potentially make use of a templated function to help you iterate over two sequences (this will allow any Sequence, not just strings):
func iterateTwo<S: Sequence>(seq1: S, seq2: S, block: (S.GeneratorType.Element, S.GeneratorType.Element) -> ()) {
var gen1 = seq1.generate()
var gen2 = seq2.generate()
while (true) {
var possibleElement1 = gen1.next()
var possibleElement2 = gen2.next()
if possibleElement1 && possibleElement2 {
block(possibleElement1!, possibleElement2!)
}
else {
break
}
}
}
Then you can simply do:
var sameplace = 0
iterateTwo(word1, word2) { (char1, char2) in
if char1 == char2 {
sameplace += 1
}
}
Upvotes: 3