2

I am trying to write a function to change a string written in Snake Case to Camel Case, but running into an error.

function snakeToCamel(string) {
    arr = [...string];
    for (i of arr) {
        if (i === "_") {
            let upperCaseLetter = arr[i+1].toUpperCase();
            arr.splice(i+1,1,upperCaseLetter);
            arr.splice(i,1)
        }
    };
    return arr;
}

The error is here. I can't find what is wrong in the line stated in the error. What is going on?

snakeToCamel("you_dont_know")
snake-to-camel.js:5 Uncaught TypeError: Cannot read property 'toUpperCase' of undefined
    at snakeToCamel (snake-to-camel.js:5)
    at <anonymous>:1:1
1
  • learn to debug.... for (i of arr) { console.log(i, i + 1, arr[i+1]); Commented Nov 2, 2020 at 17:12

4 Answers 4

1

In a for-of loop, the control variable is the array element, not an index. So i in your example is a string. So arr[i+1].toUpperCase(); will do string concatenation and try to look up a property with a name like s1, not 1.

If you want to use the index, you want a for loop or a forEach call (or even map, since that's kind of what you're doing), not a for-of loop.

A couple of other notes:

  • You need to be sure to declare your variables; right now, your code is falling prey to what I call The Horror of Implicit Globals, creating a global called arr. Add const or let before arr.

  • You don't put ; after blocks attached to control-flow statements. (You can have them there, because empty statements are allowed, but they're not supposed to be there.)

For example, using a for loop:

function snakeToCamel(string) {
    // `const` because we never reassign `arr`
    const arr = [...string];
    // Traditional `for` so we have the index
    for (let i = 0, len = arr.length; i < len; ++i) {
        const ch = arr[i];
        if (ch === "_") {
            if (i === len - 1) {
                // Trailing _, just remove it
                arr.splice(i, 1);
                --i;
                --len;
            } else {
                let upperCaseLetter = arr[i + 1].toUpperCase();
                // You can remove the _ and the lowr case letter
                // in a single `splice` rather than multiple ones
                arr.splice(i, 2, upperCaseLetter);
                --i; // Need to do this to allow for multiple `_` in a row
                --len;
            }
        }
    };
    return arr;
}
console.log(snakeToCamel("one_two__three_"));

Or using map:

function snakeToCamel(string) {
    let lastWasUnderscore = false;
    const result = [...string]
        .map(ch => {
            const thisIsUnderscore = ch === "_";
            if (lastWasUnderscore && !thisIsUnderscore) {
                lastWasUnderscore = false;
                return ch.toUpperCase(); // or `.toLocaleUpperCase()`
            }
            lastWasUnderscore = thisIsUnderscore;
            return thisIsUnderscore ? null : ch;
        })
        .filter(ch => ch !== null);
    return result;
}
console.log(snakeToCamel("one_two__three_"));

Sign up to request clarification or add additional context in comments.

Comments

0

You were actually fairly close to the solution!

Instead of using a for-of loop I would suggest you use a normal for loop. This way you can access the index i

function snakeToCamel(string) {
    const arr = [...string];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === "_") {
            let upperCaseLetter = arr[i+1].toUpperCase();
            arr.splice(i+1,1,upperCaseLetter);
            arr.splice(i,1)
        }
    }
    return arr.join("");
}

Comments

0

Here's the code I wrote. (needs to be refined for DRY principle)

function STC(string) {
    const arr = [...string];
    let output = '';
    for (const letter of arr) {
        if (letter == '_') {
            output += arr[arr.indexOf(letter)+1].toUpperCase()
            arr.splice(arr.indexOf(letter), 1)
        } else {
            output += letter;
        }
    }; return output;
}

I just add to the string instead of an array. I also delete the underscore. Tell me if it works.

Comments

0

function snakeToCamel(string) {
    const arr = [...string];
    arr.forEach((v, i) => {
       if (v === "_") {
            arr.splice(i+1,1, arr[i+1].toUpperCase());
            arr.splice(i,1)
        }
    });
    return arr.join("");
}

const result = snakeToCamel('a_b_c');
console.log(result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.