Last active
November 23, 2024 12:30
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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