2

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?

2
  • Your code count only identical characters at the same position. Is that what you intended? Commented Jul 26, 2014 at 19:26
  • @MartinR I think yes, because he's adding one to the variable sameplace. Commented Jul 26, 2014 at 19:27

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Quite impressive that Zip2 does the right thing, treating a String as an array of Characters, even if you mix a grapheme cluster with a ASCII character in the same position it still works: "a😄abcd🇩🇪" and "🇩🇪😄axcy🇩🇪".
3

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.Indexs 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
    }
}

Comments

0

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
    }
}

3 Comments

Just keep in mind that creating an 2 new arrays for the entire words each time is going to be computationally expensive. Even creating the arrays once is more expensive than is necessary but you should at least create the arrays once outside of the loop.
Also note that Array(word1) gives you an array of Character which might have a length that is different from word1.utf16Count (try word1 = "😄abcd").
@MartinR Well, the asker said that he knows the words will only contain Roman characters, so that shouldn't be a concern in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.