in Books, Doing Books, How to Solve it by Computer

How to Solve it by Computer #11

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.

Write a Comment

Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.