First we start with a starting sequence. Which evenly distributes the values:
user=> (take 2 (repeat (int (/ 1 2)))) (0 0)
Then we need the reminding values which can be calculated like this:
user=> (rem 1 2) 1
Afterwards we just generate a new sequence with X=1 one and Y=n-X zeros:
user=> (into (take (- 2 (rem 1 2)) (repeat 0)) (take (rem 1 2) (repeat 1))) (1 0)
Now we just need to map this and got our desired output:
user=> (map + (take 2 (repeat (int (/ 1 2)))) (into (take (- 2 (rem 1 2)) (repeat 0)) (take (rem 1 2) (repeat 1)))) (1 0)
That’s quite unreadable, therefore I’ll write a short function:
(defn get-whitespace-distribution "Returns a coll with the distribution of additional white spaces" [n-whitespace needed-whitespace] (let [rem-whitespace (rem needed-whitespace n-whitespace)] (map + (take n-whitespace (repeat (int (/ needed-whitespace n-whitespace)))) (into (take (- n-whitespace rem-whitespace) (repeat 0)) (take rem-whitespace (repeat 1))))))
And the function in action:
user=> (get-whitespace-distribution 2 1) (1 0) user=> (get-whitespace-distribution 2 5) (3 2)
Works fine. Ok, the next step is to insert these additional white spaces. That is, we go into a list, take the first whitespace, insert additional one and go the next one.
(defn insert-whitespace "Insert the amount of additional whitespaces given by whitespace-distribution into the provided sentence" [sentence whitespace-distribution] (loop [rest-sentence sentence rest-distribution whitespace-distribution new-sentence nil] (if (seq rest-sentence) (if (not= (first rest-sentence) \space) (recur (next rest-sentence) rest-distribution (conj new-sentence (first rest-sentence))) (recur (next rest-sentence) (next rest-distribution) (into new-sentence (take (inc (first rest-distribution)) (repeat \space))))) new-sentence)))
The idea is pretty basic. We iterate through the sentence, if we see a whitespace, we add our additional white spaces, else we just add the current character.
Let’s see if it works:
user=> (insert-whitespace sentence (get-whitespace-distribution 2 1)) (\a \space \s \i \space \space \s \i \h \T) user=> (insert-whitespace sentence (get-whitespace-distribution 2 2)) (\a \space \space \s \i \space \space \s \i \h \T) user=> (insert-whitespace sentence (get-whitespace-distribution 2 3)) (\a \space \space \s \i \space \space \space \s \i \h \T)
Looks good, now let’s generalize the function:
(defn left-right-justify-line "Returns a split text of lines justified" [line n] (let [clean-line (map delete-right-spaces (wrap-word line n))] (map #(left-right-justify % n) clean-line)))
It just applies all the functions on it. And here’s the function in action:
user=> (map #(apply str (reverse %)) (left-right-justify-line "This is a sentence which is quite long" 10)) ("" "quite long" "which is" "sentence" "This is a")
Works. It have the feeling that I made it harder than it’s actually is :D but it was a good learning experience.