Skip to content

Instantly share code, notes, and snippets.

@davepkennedy
Last active December 1, 2016 14:38
Show Gist options
  • Save davepkennedy/ca7e724ccbcd3f963db6f589a8b79a3a to your computer and use it in GitHub Desktop.
Save davepkennedy/ca7e724ccbcd3f963db6f589a8b79a3a to your computer and use it in GitHub Desktop.
Create anagrams in Scala
package io.github.davepkennedy
/**
* Created by dakennedy on 29/11/2016.
*/
object Anagrammer {
def insertAt[T](element: T, position: Int, collection: List[T]): List[T] = {
val (left,right) = collection.splitAt(position)
left ++ List(element) ++ right
}
def anagram[T] (l: List[T]): List[List[T]] = l match {
case Nil => Nil
case h :: t =>
anagram(t) match {
case Nil => List(List(h))
case permutations =>
for {
permutation <- permutations
i <- 0 to permutation.length
} yield insertAt(h, i, permutation)
}
}
def anagram (word: String): List[String] = anagram(word.toList) map (_.mkString)
}
package io.github.davepkennedy
import org.scalatest.{FlatSpec, Matchers}
/**
* Created by dakennedy on 29/11/2016.
*/
class AnagrammerSpec extends FlatSpec with Matchers {
def fac (n: Int): Int = n match {
case 1 => 1
case _ => fac(n-1) * n
}
"Anagrammer" should "produce a number of anagrams equivalent to the factorial" in {
val anagrams = Anagrammer.anagram("abcd")
anagrams.length should be (fac (4))
}
"Anagrammer" should "produce unique anagrams" in {
val anagramList = Anagrammer.anagram("abcd")
val anagramSet = Set (anagramList:_*) // Simple filter of duplicates
anagramList.length should be (anagramSet.size)
}
}
package io.github
import scala.annotation.tailrec
/**
* Created by dakennedy on 30/11/2016.
*/
package object davepkennedy {
def anagram (word: String): List[String] = {
def mingle (char: Char, accum: List[List[Char]]): List[List[Char]] = accum match {
case Nil => List (List (char))
case _ => accum flatMap {
chars => for {
i <- 0 to chars.length
} yield {
val (left, right) = chars.splitAt(i)
left ++ List (char) ++ right
}
}
}
@tailrec
def recurse (chars: List[Char], accum: List[List[Char]] = List.empty): List [List[Char]] = chars match {
case Nil => List.empty
case List (c) => mingle (c, accum)
case h :: t => recurse(t, mingle (h, accum))
}
recurse (word.toList) map (_.mkString(""))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment