1

I want to make a function which compares strings. I don't want to use equal operators (==), I want it worked only with Swift language.

First I made a function which takes 2 strings, and returns bool type. then I looped these strings with for in syntax. And want to compare these characters, if strings have equal value, it should return true, if not, then false. Is there any better way?

func isEqual(str1:String, str2:String) -> Bool {
    var result = false

    for char in str1 {

    }
    for char2 in str2 {

    }
    //Compare characters.
    return result
}
Jørgen R
  • 10,568
  • 7
  • 42
  • 59
alphonse
  • 687
  • 1
  • 6
  • 16

2 Answers2

5

== works fine with Strings in Swift. For educational purposes (as I conclude from your comment "because I'm practicing...") you can implement it as:

func myStringCompare(str1 : String, str2 : String) -> Bool {

    if count(str1) != count(str2) {
        return false
    }
    for (c1, c2) in zip(str1, str2) {
        if c1 != c2 {
            return false
        }
    }
    return true
}

zip(str1, str2) returns a sequence of pairs from the given sequences, this is a convenient way to enumerate the strings "in parallel".

Once you have understood how it works, you can shorten it, for example to:

func myStringCompare(str1 : String, str2 : String) -> Bool {

    return count(str1) == count(str2) && !contains(zip(str1, str2), { $0 != $1 })
}

Comparing the string length is necessary because the zip() sequence terminates as soon as one of the strings is exhausted. Have a look at @drewag's answer to In Swift I would like to "join" two sequences in to a sequence of tuples for an alternative Zip2WithNilPadding sequence.

If you don't want to use the built-in zip() function (again for educational/self-learning purposes!) then you can use the fact that Strings are sequences, and enumerate them in parallel using the sequence generator. This would work not only for strings but for arbitrary sequences, as long as the underlying elements can be tested for equality, so let's make it a generic function:

func mySequenceCompare<S : SequenceType where S.Generator.Element : Equatable>(lseq : S, rseq : S) -> Bool {

    var lgen = lseq.generate()
    var rgen = rseq.generate()

    // First elements (or `nil`):
    var lnext = lgen.next()
    var rnext = rgen.next()
    while let lelem = lnext, relem = rnext {
        if lelem != relem {
            return false
        }
        // Next elements (or `nil`):
        lnext = lgen.next()
        rnext = rgen.next()
    }

    // Are both sequences exhausted?
    return lnext == nil && rnext == nil
}

Tests:

mySequenceCompare("xa", "xb")  // false
mySequenceCompare("xa", "xa")  // true
mySequenceCompare("a", "aa")   // false
mySequenceCompare("aa", "a")   // false
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • thnkas Martin for a great lesson!! It really helped me to understand swift. I'm also trying to put those characters to a new array and compare each items in array. :) thank you. – alphonse Jun 02 '15 at 12:47
2

My solution differ a little as I didn't know about the zip operator, I guess is not as efficient as the one post by Martin great use of tuple.

Great question alphonse

func isEqual(str1:String, str2:String) -> Bool {
    if count(str1) != count(str2){
        return false
    }
    for var i = 0; i < count(str1); ++i {
        let idx1 = advance(str1.startIndex,i)
        let idx2 = advance(str2.startIndex,i)
        if str1[idx1] != str2[idx2]{
           return false
        }
    }
    return true
}

As pointed by Martin each string needs its own index, as explained by him: "The "trick" is that "" is an "extended grapheme cluster" and consists of two Unicode code points, but counts as one Swift character."

Link for more details about extended grapheme cluster

Icaro
  • 14,585
  • 6
  • 60
  • 75
  • You must not use the `idx` created from `str1` with a different string `str2`. Try `isEqual("foo", "foo")` :) – Martin R Jun 02 '15 at 12:12
  • 1
    Very trick, I try few different options but I didn't use the emoticons, thanks I will update it – Icaro Jun 02 '15 at 12:16
  • Now it works :) – The "trick" is that the "Regional Indicator" "" is an "extended grapheme cluster" and consists of *two* Unicode code points, but counts as *one* Swift character (in contrast to Foundation NSString, where it counts as *four* UTF-16 `unichar`) – Martin R Jun 02 '15 at 12:18
  • Thanks @MartinR just learn something new that may avoid a very difficult bug to find in the future – Icaro Jun 02 '15 at 12:25
  • @alphonse it helped me too, to be honest wasn't trivial come up with this code and in the end I learned this new think about strings I didn't know – Icaro Jun 02 '15 at 12:33