4
\$\begingroup\$

Given two strings with the same length, we check how many chars on the same positions are different. For example: ABCD and ABBD should return 1. Here is a link to a gist with tests, to have a better understanding of what I'm building. Here is my solution:

object Hamming {

  def compute(str1: String, str2: String):Int = {
    if (str1.length != str2.length)
      throw new IllegalArgumentException("Strings have different length")
    (0 to str1.length - 1).filter(i => str1(i) != str2(i)).size
  }

}
\$\endgroup\$
1
  • \$\begingroup\$ It's vaguely entertaining to see an Exercism question here. \$\endgroup\$
    – Trevoke
    Commented Aug 22, 2016 at 13:10

2 Answers 2

4
\$\begingroup\$

How about this variant?

object Hamming {

    def apply(a: String, b: String): Int = if (a.length != b.length) {
        throw new IllegalArgumentException(s"Strings a=$a and b=$b have different length.")
    } else a.zip(b).count {
        case (charA, charB) => charA != charB
    }

}

The zip-function does create a new collection of tuples with two corresponding chars side by side in every tuple. (Char, Char) The count-function counts the number of elements for which a boolean evaluation function, passed as an argument, returns true. This should work not only for characters, because it uses pattern matching. Also if there are two arguments of the same type (e.g. for comparison) and I cannot further specify what they are, then I like to name them a and b. I cannot tell if this solution is faster than yours, but I don't think there will be a significant difference.

P.S.:

  • I see the function is named compute. Thats really general and abstract. I named it apply. It can be called like this: Hamming("Alice", "Bob")
  • Look at what I did with the brackets.
  • If you would like to use the function for other sequences than characters you can change the snippet to this:

    def apply(a: Seq[_], b: Seq[_]): Int = if (a.size != b.size) {
        throw new IllegalArgumentException("Parameters have different length.")
    } else a.zip(b).count {
        case (charA, charB) => charA != charB
    }
    
\$\endgroup\$
3
\$\begingroup\$

Note of warning: I haven't done Scala in a while. The style may have changed, or I may have never known the right one, so I could be wrong.

It looks good, except for two things:

  1. Please, put brackets around one-line ifs. It makes things much easier to keep track of in the long run, even if you don't need it now. Before you say "this is just a project to learn the language", if you get into good habits now, you won't have to break bad ones later.
  2. You have a pair of newlines that have no purpose after the beginning and before the end of the object definition

Aside from that, it looks good! I like the 'algorithm' you chose to use; it's actually quite clever and easy to understand.

\$\endgroup\$
2
  • \$\begingroup\$ About if block, I know its a good practice to wrap one liners in javascript. I'm not sure about Scala, I've seen a lot of good code where people didn't do this, so I picked up that style. Maybe someone will have something to say about this case \$\endgroup\$
    – HeeL
    Commented Jul 1, 2015 at 9:42
  • \$\begingroup\$ @HeeL It's generally a better idea, for lots of reasons -- you see people talking about it in Java, C#, Javascript -- pretty much every language where you can wrap brackets around if blocks, it's said you should. I'd assume the same extends to Scala. \$\endgroup\$
    – anon
    Commented Jul 1, 2015 at 9:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.