Free Code Camp Algorithmic Challenges Part 8

This is part 8 of a series in which I give solutions to the Free Code Camp Algorithmic challenges. Don't look at this post until you've solved these challenges yourself! You've been warned. :)

Here are the links for part 1, part 2, part 3, part 4, part 5, part 6, and part 7. You can also look at the github repo with all my solutions here.

Also, I'm using whatever libraries I feel like using (just ramda in this post) and any new JavaScript features I like for all of these challenges, something you can't do at freecodecamp.com.

Ok, with all that out of the way, Let's get on to the next challenges. :)

Diff Two Arrays

Ok, we've been asked to write a function that takes two arrays, and returns an array holding elements that show up in one or the other array, but not both.

For example f([1, 2, 3], [2, 3, 4]) would return [1,4] and f([42, 86, 'hike!'], [86, 'hike!']) would return [42].

Code code code code!

const  
    xor = (a, b) => (a || b) && !(a && b)

module.exports = (xs, ys) =>  
    xs.concat(ys).filter(x =>
        xor(xs.includes(x), ys.includes(x)))

xor is an exclusive or, meaning that if either a or b are true xor will return true, but if both or neither are true then xor returns false.

Our function takes two arrays, xs and ys, concats them, then filters the resulting array. Elements only pass the filter if they're contained in xs but not in ys or vice versa.

Roman Numeral Converter

This one asks us to write a function that converts a number from 0 to 9999 to a roman numeral.

I know how to convert a number from 0 to 9 so I created a table for it:

const  
    ones_table = {
        '0': '',
        '1': 'I',
        '2': 'II',
        '3': 'III',
        '4': 'IV',
        '5': 'V',
        '6': 'VI',
        '7': 'VII',
        '8': 'VIII',
        '9': 'IX'
    },

If a number is from 10 to 99, I convert the ones place like normal and I use this table for the tens place:

    twos_table = {
        '0': '',
        '1': 'X',
        '2': 'XX',
        '3': 'XXX',
        '4': 'XL',
        '5': 'L',
        '6': 'LX',
        '7': 'LXX',
        '8': 'LXXX',
        '9': 'XC'
    },

For example, 76 converts to LXXVI. The 7 converts to LXX, and the 6 converts to VI. It's a simple conversion of each digit.

I can write a similar table for the hundreds place:

    threes_table = {
        '0': '',
        '1': 'C',
        '2': 'CC',
        '3': 'CCC',
        '4': 'CD',
        '5': 'D',
        '6': 'DC',
        '7': 'DCC',
        '8': 'DCCC',
        '9': 'CM'
    }

And the thousands place is easy, it's just the letter M times the digit. So 4000 converts to MMMM, 2000 converts to MM, etc.

So now you know how to do this conversion by hand. 3264 converts to MMMCCLXIV, 1047 converts to MXLVII, 4456 converts to MMMMCDLVI, and so on.

Here's how I do it in the code:

const  
    R = require('ramda')

module.exports =  
    R.pipe(
        R.toString,
        R.split(''),
        R.reverse,
        R.adjust(x => ones_table[x], 0),
        R.adjust(x => twos_table[x], 1),
        R.adjust(x => threes_table[x], 2),
        R.adjust(
            R.pipe(
                R.repeat('M'),
                R.join('')),
            3),
        R.reverse,
        R.join(''))

There are a lot of steps here, but each one is very simple:

First we convert the number to a string. Then we split the string into a character array. For example, 1234 would be converted to [1, 2, 3, 4].

Next we reverse the string so that the digit in the first place is at index 0, the digit in the second place is at index 1, and so on. For example, ['3', '5', '4'] would get converted to ['4', '5', '3']

Then we convert the digit at the first place using adjust and our ones table. For example, ['5', '6', '7', '9'] would get converted to ['V', '6', '7', '9'].

Then we convert the digit at the second place using adjust and our twos table. If there is no value at that index (meaning the array only has one number) adjust doesn't do anything to the array. For example, ['V', '6', '7', '9'] would get converted to ['V', 'LX', '7', '9'] but ['III'] would remain unchanged.

We do the exact same thing for the third place number as we did for the second place number. but we use a function to do the conversion for the fourth place.

That function just repeats the letter M a given number of times. Otherwise it's just like the adjust calls above.

By the way, R.repeat('M') returns an array of M's, so thats why we need to use R.join('') to turn our array into a string.

Finally, we reverse the array so things are in the correct order, and join up the array into a string. For example, ['VI', 'L', 'D'] would get turned into 'DLVI'.

Ok, that's probably enough for one post. More to come in later posts!

Looking for a software developer?