14 October 2021

Solving Problems in Clojure

Just a few little functional adventures.

What follows are little mini problems I solved in order to finished Day 2, 2018 of The Advent of Code.

Problem 1

Identify strings that have n instances of any character.

Cases:

  1. abcdef has no repeated characters.
  2. abcdee has 2 e.

Solution:

  1. Sort the input
  2. Partition the input by character
  3. Remove the partitions of incorrect length
  4. Are any partitions remaining?
(defn has-n-repeats? [n input]
  (as-> (sort input) $
        (partition-by char $)
        (filter #(= n (count %)) $)
        (not (empty? $))))

Problem 2

Count differences at corresponding positions between two strings.

Cases:

  1. abcde and fghij differ at all five locations.
  2. fghij and fguij differ at one location.

Naive Solution: use set operations (union, intersection) to see how different the strings are.

Advanced Case:

  1. xrecqmdonskvzupalfkwhjctdb and xrlgqmavnskvzupalfiwhjctdb differ at five positions

Solution:

In the advanced case, both strings have repeated characters, so sets aren't helpful.

Description:

  1. Interleave the two strings
  2. Partition the interleaved strings in character pairs
  3. remove pairs that are equal
  4. count the remaining pairs

Data Flow for fghij and fguij:

  1. (f f g g h u i i j j)
  2. ((f f) (g g) (h u) (i i) (j j))
  3. ((h u))
  4. 1

Implentation 1:

(->> (interleave a b)
     (partition 2)
     (remove #(= (first %) (second %)))
     (count))

Implementation 2:

(->> (interleave a b)
     (partition 2)
     (remove #(apply = %))
     (count))

Implementation 3:

(def equal? (partial apply =))

(->> (interleave a b)
     (partition 2)
     (remove equal?)
     (count))

Problem 3:

List characters that are equal at corresponding positions between two strings (preserving order of appearance).

Cases:

  1. fghij and fguij share fgij.

Solution:

  1. Interleave the two strings
  2. Partition the interleaved strings in character pairs
  3. filter for pairs that are equal
  4. take the first of each pair
  5. concatenate a string
(defn common-chars [a b]
  (->> (interleave a b)
       (partition 2)
       (filter equal?)
       (map first)
       (apply str)))

Problem 4:

Among a list of strings, find the two that differ by one character at a single character position and return the common characters.

Solution:

  1. List comprehension of the diff-count between every combination of strings
  2. Limit result where diff-count result is 1
  3. Return the common-chars of that combination.
(defn common-between-diff-by-one [inputs]
  (first
    (for [x inputs
          y inputs
          :when (= (diff-count x y) 1)]
      (common-chars x y))))