The idea for this post came to me when I completed the Codewars challenge: ‘Help the Bookseller’.
I’ve been doing Codewars Katas for a while now, as part of my quest to learn computing coding and although I have completed quite a lot of Katas, I have found that the possible practical application of the solution often eludes me. However, I really liked the concept of ‘Help the Bookseller’ and think I can see some possible uses for knowing how to do something like this. I haven’t had to try out any of these use cases yet but I’m going to have a go at explaining my method and maybe this might help you too – if you ever need to do something similar!
Here is what the Kata asks us to do:
A bookseller has lots of books classified in 26 categories labelled A, B, … Z. Each book has a code c of 3, 4, 5 or more characters. The 1st character of a code is a capital letter which defines the book category.
In the bookseller’s stocklist each code c is followed by a space and by a positive integer n (int n >= 0) which indicates the quantity of books of this code in stock.
For example, an extract of a stocklist could be:
[pastacode lang=”javascript” manual=”L%20%3D%20%7B%22ABART%2020%22%2C%20%22CDXEF%2050%22%2C%20%22BKWRK%2025%22%2C%20%22BTSQZ%2089%22%2C%20%22DRTYM%2060%22%7D” message=”” highlight=”” provider=”manual”/]
You will be given a stocklist (e.g.: L) and a list of categories in capital letters e.g.:
[pastacode lang=”javascript” manual=”M%20%3D%20%7B%22A%22%2C%20%22B%22%2C%20%22C%22%2C%20%22W%22%7D” message=”” highlight=”” provider=”manual”/]
and your task is to find all the books in stocklist L with codes belonging to each category of M and to sum their quantity according to each category.
For the lists L and M of example you have to return the string (in Haskell/Clojure/Racket/Prolog a list of pairs):
[pastacode lang=”javascript” manual=”(A%20%3A%2020)%20-%20(B%20%3A%20114)%20-%20(C%20%3A%2050)%20-%20(W%20%3A%200)” message=”” highlight=”” provider=”manual”/]
Oh and if L or M are empty return an empty string.
OK this took me a while to understand. However, after re-reading it a few times I got what they were after:
Find all the items in list L which begin with each of the letters in list M and add together the total quantity of items that begin with each letter.
The steps I reckoned this would take to achieve the required answer were:
Here we go (using Javascript):
[pastacode lang=”javascript” manual=”%0As%20%3D%20%5B%22BBAR%20150%22%2C%20%22CDXE%20515%22%2C%20%22BKWR%20250%22%2C%20%22BTSQ%20890%22%2C%20%22DRTY%20600%22%5D%0Am%20%3D%20%5B%22A%22%2C%20%22B%22%2C%20%22C%22%2C%20%22D%22%5D%0A%0A%0A” message=”” highlight=”” provider=”manual”/]
[pastacode lang=”javascript” manual=”%20%20%20%20function%20stockList(s%2C%20m)%20%7B%0A%20%20%20%20%20%20%20if%20(s.length%20%3D%3D%3D%200%20%7C%7C%20m.length%20%3D%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22%22%3B%0A%20%20%20%20%20%20%7D” message=”” highlight=”” provider=”manual”/]
Reduce is a good method of creating an object with key-value pairs from an array, although by no means the only way.
[pastacode lang=”javascript” manual=”let%20totals%20%3D%20s.reduce((accum%2C%20curr)%20%3D%3E%20%7B%0A%20%20%20%20if%20(!accum%5Bcurr%5B0%5D%5D)%20%7B%0A%20%20%20%20%20%20accum%5Bcurr%5B0%5D%5D%20%3D%200%3B%0A%20%20%20%20%7D%0A%20%20%20%20accum%5Bcurr%5B0%5D%5D%20%2B%3D%20%2Bcurr.split(%22%20%22)%5B1%5D%3B%0A%20%20%20%20return%20accum%3B%0A%20%20%7D%2C%20%7B%7D)%3B%0A” message=”” highlight=”” provider=”manual”/]
Within the reduce function we check if the totals object we are creating contains the current item in s we are dealing with, and if it doesn’t we set it as a key and its value to zero. Then when we have created it (or if it already exists) we need to add the quantity of that item. This we can establish by separating the current item string into two parts (by splitting it where the space between the code string and the amount is). The quantity to add is then the item at index 1 of the split array.
If you run console.log(totals) at this point you would get this:
[pastacode lang=”javascript” manual=”%7B%20B%3A%201290%2C%20C%3A%20515%2C%20D%3A%20600%20%7D” message=”” highlight=”” provider=”manual”/]
This is good – we have our categories and the total number of items in these categories.
[pastacode lang=”javascript” manual=”let%20result%20%3D%20m.map((x)%20%3D%3E%20%7B%0A%09%20%20%20%20%20%20%20%20%20return%20%60(%24%7Bx%7D%20%3A%20%24%7Btotals%5Bx%5D%20%7C%7C%200%7D)%60%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A” message=”” highlight=”” provider=”manual”/]
If you run console.log(result) at this point you would get this:
[pastacode lang=”javascript” manual=”%5B%20′(A%20%3A%200)’%2C%20′(B%20%3A%201290)’%2C%20′(C%20%3A%20515)’%2C%20′(D%20%3A%20600)’%20%5D” message=”” highlight=”” provider=”manual”/]
This is great we’re nearly there – we just need to format it as requested.
[pastacode lang=”javascript” manual=”result.join(%22%20-%20%22)” message=”” highlight=”” provider=”manual”/]
This returns the items in result as a string separated by hyphens.
And that’s it!
Here it is all put together:
[pastacode lang=”javascript” manual=”function%20stockList(s%2C%20m)%20%7B%0A%20%20if%20(s.length%20%3D%3D%3D%200%20%7C%7C%20m.length%20%3D%3D%3D%200)%20%7B%0A%20%20%20%20return%20%22%22%3B%0A%20%20%7D%0A%20%20let%20totals%20%3D%20s.reduce((accum%2C%20curr)%20%3D%3E%20%7B%0A%20%20%20%20if%20(!accum%5Bcurr%5B0%5D%5D)%20%7B%0A%20%20%20%20%20%20accum%5Bcurr%5B0%5D%5D%20%3D%200%3B%0A%20%20%20%20%7D%0A%20%20%20%20accum%5Bcurr%5B0%5D%5D%20%2B%3D%20%2Bcurr.split(%22%20%22)%5B1%5D%3B%0A%20%20%20%20return%20accum%3B%0A%20%20%7D%2C%20%7B%7D)%3B%0A%20%20let%20result%20%3D%20m.map((x)%20%3D%3E%20%7B%0A%20%20%20%20return%20%60(%24%7Bx%7D%20%3A%20%24%7Btotals%5Bx%5D%20%7C%7C%200%7D)%60%3B%0A%20%20%7D)%3B%0A%20%20return%20result.join(%22%20-%20%22)%3B%0A%7D” message=”” highlight=”” provider=”manual”/]
It can be simplified – for example steps 3 and 4 can be done in a single step.
There are no doubt countless other ways to achieve the correct end result, but I feel this way is quite simple to follow and could have variations of the request incorporated quite easily. For example, if the result information was requested in a different format that would be straightforward to implement.