Skip to content

Instantly share code, notes, and snippets.

@pilosus
Last active November 23, 2024 12:30
Show Gist options
  • Save pilosus/aae8f5b1907cd5eefdea7581314831c5 to your computer and use it in GitHub Desktop.
Save pilosus/aae8f5b1907cd5eefdea7581314831c5 to your computer and use it in GitHub Desktop.
String compression based on substitution of the sequences of repetitive chars with the char itself and, if the sequence is longer than 1 char, number of repetition
(ns compress
"Compress given string so that consecutive characters are grouped into
a character itself and number of repetitions if the count is more
than one:
(compress 'aaaBBccBDH')
'a3B2c2BDH'
(compress 'aaa')
'a3'
(compress '')
''
"
(:require [clojure.string :as s]))
(defn compress-partition
"Use partition-by from the standard library"
[s]
(->> s
(partition-by identity)
(map
(fn [v]
(let [char (first v)
counter (count v)]
(if (> counter 1)
(str char counter)
(str char)))))
s/join))
(defn compress-recur
"loop/recur implementation"
[s]
(loop [xs (seq s)
prev nil
counter 1
result []]
(let [curr (first xs)]
(cond
;; terminate?
(empty? xs)
(let [dump (if (> counter 1) (str counter prev) (str prev))]
(s/join (conj result dump)))
;; same character as one iteration before, inc counter
(and (= prev curr) (not (nil? prev)))
(recur (rest xs) curr (inc counter) result)
;; current character is different as previous one
(and (not (= prev curr)) (not (nil? prev)))
(let [dump (if (> counter 1) (str counter prev) (str prev))]
(recur (rest xs) curr 1 (conj result dump)))
;; else, e.g. first iteration with prev nil
:else
(recur (rest xs) curr counter result)))))
(defn compress-regexp
"Use regex groups to replace sequences with more than 1 repetitive char"
[s]
(s/replace
s
#"(.)\1+"
(fn [[full-seq matching-char]]
(str matching-char (count full-seq)))))
;; FP-Police recommendatation
;; If you are a sensitive person, please leave the page NOW.
(defn compress-nested-loop
"Iterate over chars of a string, on each iteration start a nested loop
to find an index of the last char in a sequence of repetitive chars,
then recur with the outer loop at this found index to find the next
sequence."
[s]
(let [result (atom [])
max-idx (count s)]
(loop [read-idx 0]
(when (< read-idx max-idx)
(let [curr (nth s read-idx)
start-seq-idx read-idx
end-seq-idx
(loop [write-idx read-idx]
(if (and (< write-idx max-idx) (= curr (nth s write-idx)))
(recur (inc write-idx))
write-idx))]
(swap! result conj curr)
(when (> (- end-seq-idx start-seq-idx) 1)
(swap! result conj (str (- end-seq-idx start-seq-idx))))
(recur end-seq-idx))))
(s/join @result)))
(defn compress-reduce
"It's a shame.
But it's here to remind that we all are able to write ugly code"
[s]
(let [prev (atom nil)
counter (atom 1)
result
(reduce
(fn [acc curr]
(cond
;; same char
(= @prev curr)
(do
(swap! counter inc)
(reset! prev curr)
acc)
;; char changed
(and (not (= @prev @counter)) (not (nil? @prev)))
(let [dump (if (> @counter 1) (str @prev @counter) (str @prev))
_ (reset! prev curr)
_ (reset! counter 1)]
(conj acc dump))
;; else
:else
(do
(reset! prev curr)
acc)))
[]
(seq s))]
(s/join
(conj
result
(if (> @counter 1)
(str @prev @counter)
(str @prev))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment