Scala mastermind solver, which is the most scala-ish
All this zipping and unzipping looks really convoluted. I think the problem here is getting too much enamored with what you can do with a Scala collection instead of focusing on the problem at hand.

One way of decreasing zip cost is to do it on a view. This way, no intermediary collection is created -- though that depends a bit on the methods being called. At any rate, zip is one of these methods.

It wouldn't work on your case, however, because you then go on to partition and unzip -- I'd be wary of calling such methods on a view, because they may end up being more expensive, not less.

I think the map approach is better, because it avoids the O(n log n) sorting. A HashMap can be built in O(n), and looked up in constant time. This is how I'd do it:

object Mastermind {
  def check(guess: Symbol*)(secret: Symbol*): (Int, Int) = {
    val numOfGoodPairs = guess.view zip secret count { case (a, b) =&gt; a == b }
    val guessesForSymbol = guess.groupBy(identity).mapValues(_.size)
    val secretsForSymbol = secret.groupBy(identity).mapValues(_.size)
    val unorderedGuesses = for {
      symbol &lt;- guessesForSymbol.keys.toSeq
      secrets &lt;- secretsForSymbol get symbol
      guesses = guessesForSymbol(symbol)
    } yield secrets min guesses
    val numOfMisplaced = unorderedGuesses.sum - numOfGoodPairs
    (numOfGoodPairs, numOfMisplaced)
  }
}


The first line should be pretty fast -- it will iterate once through both guess and secret, counting each time they are equal.

Computing both maps is more expensive, but it should be cheaper than sorting. Note that mapValues return a view of the values -- it does not copy any data. This is particularly interesting because it will only compute the size of map elements for keys present in both guess and secret. It is a small optimization, but you gain it almost for free.

We avoid most of the complexity by simply subtracting the number of correct guesses from the number of unordered guesses.