HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

Simple anagram finder using Scala and some Scalaz

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simplefinderscalaanagramusingsomeandscalaz

Problem

I'd like to hear some thoughts on my simple anagram finder, written in Scala. I mainly wrote this as a first go at writing some serious Scala, and I wanted to try out the Scalaz library.

I'm coming from a Java background, with minimal experience with functional languages. Things I'd ideally like feedback on:

  • Any improvements to make it less imperative



  • Any other uses of library code, like Scalaz



I know that I've not covered all test cases, but this was enough to get me up and running.
General algorithm:

  • Parse a list of words. Turn each word into lower case, sort alphabetically and treat that as the 'signature' of the word.



  • Insert signature and word into a map, with the key being the signature, and the value being a set (or list) of words with the same signature



  • Retrieval is simply looking up a word based on its signature



Signature class

case class Stem(word: String) {
  val stem: List[Char] = word.toLowerCase.trim.toList.sortWith((e1, e2) => (e1  s.stem == stem
    case _ => false
  }

  override def hashCode = stem.hashCode

  override def toString = stem.mkString("Stem(", "", ")")
}


Notes:

I'm sure I'd be able to take the word as a parameter and manipulate it to be in alphabetical order, rather than having a stem field. I'm sure I'd have been able to omit the equals and hashCode methods then, but I couldn't work out how to do that. I think maybe because I'm using a case class here?
Anagram Finder class

import scalaz._
import Scalaz._

class AnagramFinder(words: List[String]) {
 
  implicit def string2Stem(s: String): Stem = Stem(s)
 
  val mapping = createMapping(words)
 
  def createMapping(words: List[String]) = {
    var anagrams: Map[Stem, Set[String]] = Map()
 
    words.foreach(s => anagrams = anagrams |+| Map(Stem(s) -> Set(s)))
 
    anagrams
  }
   
  def find(word: String): Option[Set[String]] = mapping.get(word)
}


Notes:

I really wanted to just have anagrams |+| Map(Stem(s) -> Set(s)) in my foreach, but

Solution

Some suggestions to improve your code:

xs.sortWith((e1, e2) => (e1 Stem doesn't work in string -> set because -> already needs an implicit conversion and you are not allowed to apply multiple ones at once. When you use tuple notation (string, set), your implicit conversion is applied.

Code Snippets

object Stem {
  def apply(word: String): Stem = {
    val stem: List[Char] = word.toLowerCase.trim.toList.sorted
    new Stem(stem)
  }
}

case class Stem private(stem: List[Char])
(Map.empty[Stem, Set[String]] /: words) {
  case (map, word) => map + (Stem(word) -> Set(word))
}
words.map(word => Map(Stem(word) -> Set(word))) reduceLeft { _|+|_ }

Context

StackExchange Code Review Q#15437, answer score: 14

Revisions (0)

No revisions yet.