The June 2016 edition of the London Clojurians coding dojo set the challenge of building a celebrity name smash, taking two “celebrities” and smashing their names together to make a weird or ammusing gestalt name.
For bonus points the challenge would include this celebrity name smash as a service and even more bonus points if using the new
clojure.spec library to put specifications around data structures and functions.
Bonus points are non-redeemable, sorry!
Although our group didnt get get any of the bonus levels, here is the blow by blow development of our code for the Celebrity Name Smash.
We created a default Clojure project to start using the following leiningen command
This created a simple project using Clojure 1.8.0. If we had chosen to use
clojure.spec as well then we would have updated the
project.clj file to use Clojure 1.9.x as a dependency instead.
The simplest way to represent a celebrity name is in a string. So we bount a name called
celebrities to a string containing the first celebrity we could think of
As we want to have two celebrties then we changed the data structure into a Clojure vector. A vector is the most flexible data structure in Clojure. So we redefined the name
celebrities to be bound to a vector of strings containing the first celebrity couple we could think of.
Each celebrity has a first and last name, so we need to split them into individual strings first.
We decided to exclude celebrities with just a single name.
From a quick Google we found the clojure.string/split function that will split a string on a given pattern, that pattern being a regular expression (regex).
The regular expression pattern
" " matches the space characters. We could have also used
#"+s" for the same results in this example, although it was felt that the space was clearer in intent.
So we wrote a function called
name-split to take a first and last name as a string and return two seperate strings, one for the first name and one for the last name.
We tested the
name-split function in the repl
We could now succesfully split the full name of a celebrity into their first and last names.
A more advanced example of splitting up words would be to use re-seq with a regex patter, as in the HHGTTG book processing example in clojure-through-code.
As the aim of our code is to create silly and weird names from celebrity names, we wont get the desired results with just the first and last names. So we take those and split them.
At first we decided to split them in half, rounding down for odd lenght names.
As a Clojure String can be used like a collection of characters, we could simply
take the first x number of characters.
The value returned is a list of characters, so we would have to combine them back into a string. Just using the
str function on the result of the
take function returned a lazy sequence. To get a string we needed to
reduce with the
To do this for a name of any length we would need to
count the string characters and divide by 2.
This code also works for names that have an odd number of characters. When the odd number of characters is divided by two, a Clojure ratio type is used to hold the result rather than return a decimal value. The
take function calculated the value of the ratio type and rounds it to the nearest whole number.
Here is a breakdown of how this code works with a name containing an odd number of characters.
After reviewing this code it seemed a little complex for what we wanted, so a quick Google gave us the
subs function. The
subs function takes a string and a starting point for the split, with an optional end point
So when we want the first part of the name we give the
subs function a start point and an end point for the sub-division. For the last part of a name we simply give the start point for the sub-division.
Hint If the
subsfunction did not deal with odd numbers of characters, then instead of dividing by 2 we could have used the
quotefunction divides the first argument by the second argument, returning the result as a whole number.
We created a function that takes the name as a argument and returns the substring for the first half of the name
We used the
let function to create a local name (symbol) called
end that points to the end position in the string, based on dividing the name by 2. Then we call the
subs fuction to get the substring from 0 to the value of
Just talking the half way point for our substring only gives one result. If we add a random element to creating our substring then we should get many more variations in results.
A slight refinement can be made by replacing
+ 1 with the
We wanted to combine two first names and two last names to make a new first & last name. So we need a similar function to create the lastname subname
This function is almost identical to the first function, however only a start position is provided to
subs function, creating a substring from the
start position to the end of the name.
Finally we call these functions from a main function named
celeb-name-smash, which takes two celebrity names as string arguments and returns a string containing the smashed name.
celeb-name-smash function has a lot of duplication, so should probably be refactored to make it more elegant. However, we ran out of time at the dojo, so I will have a look at refactoring this function as homework.
Thanks to everyone that took part in the London Clojurians dojo at Thoughworks in June 2016, especially to the organisers for getting us together and feeding us lots of pizza.
This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License, including custom images & stylesheets. Permissions beyond the scope of this license may be available at @jr0cket