Ninety-Nine Problems In Clojure Part 1 1-15

The original Ninety-Nine Prolog Problems was written by Werner Hett at the Berne University of Applied Sciences in Berne, Switzerland.  Phil Gold then adapted it to Ninety-Nine Scala Problems. I had fun reading them. It has inspired me to do a series of Ninety-Nine Problems in different languages. I’m starting with Clojure.

I’m taking a more practical approach. I use built-in library whenever possible. I use clojure-contrib as well. Because on a day to day basis, this is what we all do. They exist for a reason after all. If you feel that’s cheating. Feel free to write your own. :)

The difficulty ranking was for Prolog. The original text says

The problems have different levels of difficulty. Those marked with a single asterisk (*) are easy. If you have successfully solved the preceeding problems you should be able to solve them within a few (say 15) minutes. Problems marked with two asterisks (**) are of intermediate difficulty. If you are a skilled Proglog programmer it shouldn’t take you more than 30-90 minutes to solve them. Problems marked with three asterisks (***) are more difficult. You may need more time (i.e. a few hours or more) to find a good solution.

I think the difficulty scale for the most part is comparable in Clojure.

P01 (*) Find the last element of a list.
Example:

user=> (last [1 1 2 3 5 8])
8
P02 (*) Find the last but one element of a list.
Example:

user=> (penultimate [1 1 2 3 5 8])
5
P03 (*) Find the Kth element of a list.
By convention, the first element in the list is element 0.Example:

user=> (nth2 2 [1 1 2 3 5 8])
2
P04 (*) Find the number of elements of a list.
Example:

user=> (length [1 1 2 3 5 8])
6
P05 (*) Reverse a list.
Example:

user=> (reverse [1 1 2 3 5 8])
(8 5 3 2 1 1)
P06 (*) Find out whether a list is a palindrome.
Example:

user=> (palindrome? [1 2 3 2 1])
true
P07 (**) Flatten a nested list structure.
Example:

user=> (flatten [[1 1] 2 [3 [5 8]]])
(1 1 2 3 5 8 )
P08 (**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.Example:

user=> (compress "aaaabccaadeeee")
(\a \b \c \a \d \e)
P09 (**) Pack consecutive duplicates of list elements into sublists.
If a list contains repeated elements they should be placed in separate sublists.Example:

user=> (pack "aaaabccaadeeee")
((\a \a \a \a) (\b) (\c \c) (\a \a) (\d) (\e \e \e \e))
P10 (*) Run-length encoding of a list.
Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as tuples (N, E) where N is the number of duplicates of the element E.Example:

user=> (encode "aaaabccaadeeee")
((4 \a) (1 \b) (2 \c) (2 \a) (1 \d) (4 \e))
P11 (*) Modified run-length encoding.
Modify the result of problem P10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N, E) terms.Example:

user=> (encode-modified "aaaabccaadeeee")
((4 \a) (\b) (2 \c) (2 \a) (\d) (4 \e))
P12 (**) Decode a run-length encoded list.
Given a run-length code list generated as specified in problem P10, construct its uncompressed version.Example:

user=> (decode [[4 \a] [1 \b] [2 \c] [2 \a] [1 \d] [4 \e]])
(\a \a \a \a \b \c \c \a \a \d \e \e \e \e)
P13 (**) Run-length encoding of a list (direct solution).
Implement the so-called run-length encoding data compression method directly. I.e. don’t use other methods you’ve written (like P09′s pack); do all the work directly.Example:

user=> (encode-direct "aaaabccaadeeee")
((4 \a) (\b) (2 \c) (2 \a) (\d) (4 \e))
P14 (*) Duplicate the elements of a list.
Example:

user=> (duplicate "abccd")
(\a \a \b \b \c \c \c \c \d \d)
P15 (**) Duplicate the elements of a list a given number of times.
Example:

user=> (duplicate-n 3 "abccd")
(\a \a \a \b \b \b \c \c \c \c \c \c \d \d \d)

Comments (5)

fogusNovember 10th, 2009 at 10:46 pm

I am curious why you decided to use core functions for some (e.g. last, reverse) and wrap core functions for others (e.g. count)?

-m

[...] problems in #clojure part 1 (here, via @wmacgyver) — Attempting to solve the ninety-nine Prolog problems in #clojure Share [...]

[...] Here can be found an interesting effort to implement the 99 Prolog problems in Clojure. [...]

MNovember 11th, 2009 at 11:16 am

fogus: It was to keep in spirit of the exercise as much as possible. In case of length, the original Prolog 99 problem ask you to implement a “length” function. So I wrap it. But in case of reverse. The problem asked you to implement a “reverse” function, which clojure’s core function is in fact called reverse. So I just use it with the same name.

fogusNovember 15th, 2009 at 11:14 pm

Makes sense. Thanks for the calrification.
-m