Skip to content

Instantly share code, notes, and snippets.

@nicolegooden
Last active February 16, 2021 17:38
Show Gist options
  • Save nicolegooden/48d48cc92e14c1f94763cb2b2dec9f09 to your computer and use it in GitHub Desktop.
Save nicolegooden/48d48cc92e14c1f94763cb2b2dec9f09 to your computer and use it in GitHub Desktop.
Codewars challenge with progression of solutions

Prompt

Complete the solution so that the function will break up camel casing, using a space between words.

Example: solution("camelCasing") == "camel Casing"

Pseudocode

  • input: string
  • output: string with spaces between lowercase and uppercase letters
  • methods: reduce()
  • determine where the uppercase letters exist
  • turn string into array with split()
  • iterate through string array
  • track index of uppercase letters
  • depending on how many elements exist in the new array => return interpolation as a string, with each element inserted w/ space between

My goal:

Refactor my initial solution with consideration for space/memory and time efficiency.

There are 6 versions of my solution; the progression of my solutions and thought process are documented below, beginning with my initial solution and ending with my final solution!

Testing (Jest)

const solution = require('./index');

describe('Solution', () => {
  it('should return formatted string', () => {
    let input = 'camelCasing';
    let output = 'camel Casing';
    expect(solution(input)).toBe(output);

    input = 'helloThereItIsNicole'
    output = 'hello There It Is Nicole';
    expect(solution(input)).toBe(output);

    input = 'newyorkPizzaIsGreat';
    output = 'newyork Pizza Is Great';
    expect(solution(input)).toBe(output);
  })

  it('should account for capital at index 0', () => {
    let input = 'BerneseMountainDogsAreAwesome';
    let output = 'Bernese Mountain Dogs Are Awesome';
    expect(solution(input)).toBe(output);

    input = 'ILoveTheMountains';
    output = 'I Love The Mountains';
    expect(solution(input)).toBe(output);
  })
})

Solutions

const solution1 = (string) => {
  const splitString = string.split('');
  let capitalIndices = [];
  splitString.forEach(el => {
    if (el === el.toUpperCase()) {
      capitalIndices.push(splitString.indexOf(el));
    }
  })
  return splitString.reduce((output, el) => {
    if (!capitalIndices.includes(splitString.indexOf(el))) {
      output += el;
    } else {
      output += ' ' + el;
    }
    return output;
  }, '')
}

solution1 runtime: 5.582 seconds

Next, I realize I should make use of the optional index argument for the array iterator methods. Also, splitString makes for good readability, but takes up extra surface area in the function.

const solution2 = (string) => {
  const splitString = string.split('');
  let capitalIndices = [];
  splitString.forEach((el, i) => {
    if (el === el.toUpperCase()) {
      capitalIndices.push(i);
    }
  })
  return splitString.reduce((output, el, i) => {
    return !capitalIndices.includes(i) ? 
      output += el : output += ' ' + el;
  }, '')
}

solution2 runtime: 7.123 seconds

At this point, I am still using two array iterators, and I realize that I could perform the forEach() logic inside of reduce().

const solution3 = (string) => {
  let capitalIndices = [];
  return string.split('').reduce((output, el, i) => {
    if (el === el.toUpperCase()) {
      capitalIndices.push(i);
    }
    return !capitalIndices.includes(i) ? 
      output += el : output += ' ' + el;
  }, '')
}

solution3 runtime: 5.991 seconds - great improvement!

Now, I refactor specifically for space. That capitalIndices [] variable is an extra step I no longer need!

const solution4 = (string) => {
  return string.split('').reduce((output, el, i) => {
    if (el === el.toUpperCase()) {
      output += ' ' + el;
    } else {
      output += el; 
    }
    return output;
  }, '')
}

solution4 runtime: 5.557 seconds

const solution5 = (string) => {
  return string.split('').reduce((output, el, i) => {
    return el === el.toUpperCase() ?  
      output += ` ${el}` : output += el; 
  }, '')
}

solution5 runtime: 5.2 seconds

In my final solution below, I add logic to account for a capital letter as the first letter in the string, so that a space is not automatically inserted into the string where it doesn't need to be! I also change the ternary back to a regular if/else block for readability.

const finalSolution = (string) => {
  return string.split('').reduce((output, el, i) => {
    if (el === el.toUpperCase() && i !== 0) {
      output += ` ${el}`;
    } else {
      output += el;
    }
    return output;    
  }, '')
}

module.exports = finalSolution;

finalSolution runtime: 5.489 seconds

Big O: O(n)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment