Advertisement
Guest User

Untitled

a guest
May 15th, 2015
217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 7.28 KB | None | 0 0
  1. package forcomp
  2.  
  3. import common._
  4.  
  5. object Anagrams {
  6.  
  7.   /** A word is simply a `String`. */
  8.   type Word = String
  9.  
  10.   /** A sentence is a `List` of words. */
  11.   type Sentence = List[Word]
  12.  
  13.   /** `Occurrences` is a `List` of pairs of characters and positive integers saying
  14.    *  how often the character appears.
  15.    *  This list is sorted alphabetically w.r.t. to the character in each pair.
  16.    *  All characters in the occurrence list are lowercase.
  17.    *  
  18.    *  Any list of pairs of lowercase characters and their frequency which is not sorted
  19.    *  is **not** an occurrence list.
  20.    *  
  21.    *  Note: If the frequency of some character is zero, then that character should not be
  22.    *  in the list.
  23.    */
  24.   type Occurrences = List[(Char, Int)]
  25.  
  26.   /** The dictionary is simply a sequence of words.
  27.    *  It is predefined and obtained as a sequence using the utility method `loadDictionary`.
  28.    */
  29.   val dictionary: List[Word] = loadDictionary
  30.  
  31.   /** Converts the word into its character occurence list.
  32.    *  
  33.    *  Note: the uppercase and lowercase version of the character are treated as the
  34.    *  same character, and are represented as a lowercase character in the occurrence list.
  35.    */
  36.   def wordOccurrences(w: Word): Occurrences = {
  37.     val map = w.toLowerCase.toList.groupBy((c: Char) => c).map((t: (Char, List[Char])) => (t._1, t._2.length))
  38.     map.toList.sortWith((f: (Char, Int), s: (Char, Int)) => f._1 < s._1)
  39.   }
  40.  
  41.   /** Converts a sentence into its character occurrence list. */
  42.   def sentenceOccurrences(s: Sentence): Occurrences = wordOccurrences(s.toList.flatten.mkString)
  43.  
  44.   /** The `dictionaryByOccurrences` is a `Map` from different occurrences to a sequence of all
  45.    *  the words that have that occurrence count.
  46.    *  This map serves as an easy way to obtain all the anagrams of a word given its occurrence list.
  47.    *  
  48.    *  For example, the word "eat" has the following character occurrence list:
  49.    *
  50.    *     `List(('a', 1), ('e', 1), ('t', 1))`
  51.    *
  52.    *  Incidentally, so do the words "ate" and "tea".
  53.    *
  54.    *  This means that the `dictionaryByOccurrences` map will contain an entry:
  55.    *
  56.    *    List(('a', 1), ('e', 1), ('t', 1)) -> Seq("ate", "eat", "tea")
  57.    *
  58.    */
  59.   lazy val dictionaryByOccurrences: Map[Occurrences, List[Word]] = {
  60.     dictionary.groupBy((w: Word) => wordOccurrences(w)).withDefaultValue(List())
  61.   }
  62.  
  63.   /** Returns all the anagrams of a given word. */
  64.   def wordAnagrams(word: Word): List[Word] = dictionaryByOccurrences(wordOccurrences(word))
  65.  
  66.   /** Returns the list of all subsets of the occurrence list.
  67.    *  This includes the occurrence itself, i.e. `List(('k', 1), ('o', 1))`
  68.    *  is a subset of `List(('k', 1), ('o', 1))`.
  69.    *  It also include the empty subset `List()`.
  70.    *
  71.    *  Example: the subsets of the occurrence list `List(('a', 2), ('b', 2))` are:
  72.    *
  73.    *    List(
  74.    *      List(),
  75.    *      List(('a', 1)),
  76.    *      List(('a', 2)),
  77.    *      List(('b', 1)),
  78.    *      List(('a', 1), ('b', 1)),
  79.    *      List(('a', 2), ('b', 1)),
  80.    *      List(('b', 2)),
  81.    *      List(('a', 1), ('b', 2)),
  82.    *      List(('a', 2), ('b', 2))
  83.    *    )
  84.    *
  85.    *  Note that the order of the occurrence list subsets does not matter -- the subsets
  86.    *  in the example above could have been displayed in some other order.
  87.    */
  88.   def combinations(occurrences: Occurrences): List[Occurrences] = {
  89.     val nonSort = cartesianProd(occurrences.map((t: (Char, Int)) => combinate(t._1, t._2)))
  90.     nonSort.map((x: List[(Char, Int)]) => x.sortWith((t1: (Char, Int), t2: (Char, Int)) => t1._1 < t2._2))
  91.   }
  92.   def combinate(char: Char, occ: Int): List[(Char, Int)] = occ match {
  93.     case 0 => Nil
  94.     case n => (char, n) :: combinate(char, n - 1)
  95.   }
  96.   def cartesianProd[T](l: List[List[T]]):List[List[T]] = l match {
  97.     case Nil => List(List())
  98.     case l1 :: tail => {
  99.       val pr = cartesianProd(tail)
  100.       l1.flatMap((x: T) => pr.map((l: List[T]) => x :: l)) ::: pr
  101.     }
  102.   }
  103.   /** Subtracts occurrence list `y` from occurrence list `x`.
  104.    *
  105.    *  The precondition is that the occurrence list `y` is a subset of
  106.    *  the occurrence list `x` -- any character appearing in `y` must
  107.    *  appear in `x`, and its frequency in `y` must be smaller or equal
  108.    *  than its frequency in `x`.
  109.    *
  110.    *  Note: the resulting value is an occurrence - meaning it is sorted
  111.    *  and has no zero-entries.
  112.    */
  113.   def subtract(x: Occurrences, y: Occurrences): Occurrences = {
  114.     x.flatMap((tx: (Char, Int)) => {
  115.       y.find((ty: (Char, Int)) => tx._1 == ty._1) match {
  116.         case None => List(tx)
  117.         case Some(ty: (Char, Int)) => if (ty._2 == tx._2) Nil else List((tx._1, tx._2 - ty._2))
  118.       }
  119.     })
  120.   }
  121.  
  122.   /** Returns a list of all anagram sentences of the given sentence.
  123.    *  
  124.    *  An anagram of a sentence is formed by taking the occurrences of all the characters of
  125.    *  all the words in the sentence, and producing all possible combinations of words with those characters,
  126.    *  such that the words have to be from the dictionary.
  127.    *
  128.    *  The number of words in the sentence and its anagrams does not have to correspond.
  129.    *  For example, the sentence `List("I", "love", "you")` is an anagram of the sentence `List("You", "olive")`.
  130.    *
  131.    *  Also, two sentences with the same words but in a different order are considered two different anagrams.
  132.    *  For example, sentences `List("You", "olive")` and `List("olive", "you")` are different anagrams of
  133.    *  `List("I", "love", "you")`.
  134.    *  
  135.    *  Here is a full example of a sentence `List("Yes", "man")` and its anagrams for our dictionary:
  136.    *
  137.    *    List(
  138.    *      List(en, as, my),
  139.    *      List(en, my, as),
  140.    *      List(man, yes),
  141.    *      List(men, say),
  142.    *      List(as, en, my),
  143.    *      List(as, my, en),
  144.    *      List(sane, my),
  145.    *      List(Sean, my),
  146.    *      List(my, en, as),
  147.    *      List(my, as, en),
  148.    *      List(my, sane),
  149.    *      List(my, Sean),
  150.    *      List(say, men),
  151.    *      List(yes, man)
  152.    *    )
  153.    *
  154.    *  The different sentences do not have to be output in the order shown above - any order is fine as long as
  155.    *  all the anagrams are there. Every returned word has to exist in the dictionary.
  156.    *  
  157.    *  Note: in case that the words of the sentence are in the dictionary, then the sentence is the anagram of itself,
  158.    *  so it has to be returned in this list.
  159.    *
  160.    *  Note: There is only one anagram of an empty sentence.
  161.    */
  162.   def sentenceAnagrams(sentence: Sentence): List[Sentence] = {
  163.     def sentenceAnagramOcc(occ: Occurrences): List[Sentence] = {
  164.       val comb = combinations(occ)
  165.       comb.flatMap((o: Occurrences) => {
  166.         val dict = dictionaryByOccurrences(o)
  167.         dict match {
  168.           case Nil => List(List())
  169.           case dict => dict.flatMap((w: Word) => {
  170.             val subt = subtract(occ, o)
  171.             val s = sentenceAnagramOcc(subt)
  172.             val a = s.map((s: Sentence) => w :: s)
  173.             if (s.forall((s: Sentence) => s == Nil) && subt != Nil) {
  174.               println("FRFSGGSDGFLHUYSGFKCLVGSJYGFKLSDBGLKVHSIUDGVLKSFGVLKGSLKJVGBRSFL\nKGVSLDKHGFLKSGHFLKJHSDKLJHFLKJSDHFHKLSDHFLKJSDHFLKJSHDFJKHSDLFGHJSD")
  175.               Nil
  176.             } else a
  177.             })
  178.         }
  179.       })
  180.     }
  181.     sentenceAnagramOcc(sentenceOccurrences(sentence))
  182.   }
  183. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement