Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created December 27, 2021 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/fe78cac5bd3e9aced964234c04c711c4 to your computer and use it in GitHub Desktop.
Save ericnormand/fe78cac5bd3e9aced964234c04c711c4 to your computer and use it in GitHub Desktop.
456 PurelyFunctional.tv Newsletter

Rhyming scheme equivalence

Roses are red    A
Violets are blue B
Sugar is sweet   C
And so are you   B

English teachers like to represent the rhyming pattern of poems with letters. Each line rhymes with lines with the same letter. In this case, B lines rhyme together, but the A and C lines don't rhyme. We will call that a "ABCB" rhyming scheme. However, the choice of letters is arbitrary. We could have called it "IBPB" or "XALA".

We want a way to know if two rhyming schemes are equivalent. Write a function that returns nil if they are not equivalent and returns a map of replacements if they are equivalent.

Examples

(equiv? "ABCB" "XALA") ;=> {\A \X \B \A \C \L}
(equiv? "A" "A") ;=> {}
(equiv? "A" "B") ;=> {\A \B}
(equiv? "AB" "A") ;=> nil
(equiv? "ABB" "XXY") ;=> nil

Thanks to this site for the problem idea, where it is rated Very Hard in Java. The problem has been modified.

Please submit your solutions as comments on this gist.

To subscribe: https://purelyfunctional.tv/newsletter/

@KingCode
Copy link

(defn equiv? [sc1 sc2]
  (when (= (count sc1) (count sc2))
    (->> sc2 (map vector sc1)
         (reduce (fn [m [c1 c2 :as c1c2]]
                   (cond
                     (not (contains? m c1))
                     (conj m c1c2)
                     (not= c2 (get m c1))
                     (reduced nil)
                     :else
                     m))
                 {})
         ((fn [m] (and m (->> m (into {} (remove #(apply = %))))))))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment