Partitioning input strings by even and odd indexes

I have been trying to learn javascript for a year now, and have just embarked on HackerRank's 30 days of code. After a couple of days I finally solved this problem. Here is the task (if you click the link, press x to the signup page):

Given a string S of length N that is indexed from 0 to N-1, print its even-indexed and odd-indexed characters as space-separated strings on a single line (see the Sample below for more detail).

Sample Input

2
Hacker
Rank

Sample Output

Hce akr
Rn ak

Here is my solution. Any performance optimizations I could make here?:

function processData(input) {
//Enter your code here

//split the string into an array
let words = input.split("\n").slice(1),
odd = "",
even = "",
newStr = "";
//turn each string inside the array into its own array
let wordsArr = words.map((val) => {
return val.split("");
})
//outer loop for the outer array
for (let i = 0, len = wordsArr.length; i < len; i++){
//inner loop for the inner arrays
for (let j = 0, len2 = wordsArr[i].length; j < len2; j++){
//if the index is even or odd, add to the respective strings
if (j % 2 === 0){
even += wordsArr[i][j]
} else if (j % 2 !== 0) {
odd += wordsArr[i][j];
}

//if the end of the array is detected, print the string
//and set odd/even strings to be blank for the next iteration
if (j == len2 - 1){
newStr = ${even}${odd};
even = "";
odd = "";
console.log(newStr);
}
}
}

}

One possible solution that achieves the described result is:

${s.replace(/./g, (s, pos) => [s, ''][pos & 1])}${s.replace(/./g, (s, pos) => ['', s][pos & 1])}

...But in order to answer to your question:

// 0
let wordsArr = words.map((val) => {
return val.split("");
})

// can be rewritten as
let wordsArr = words.map(val => val.split(''))

// 1
for (let i = 0, len = wordsArr.length; i < len; i++){

// personally I use
i += 1
// following to Douglas Crockford
// this is what actually happens under the hood

// 2
if (j % 2 === 0){
even += wordsArr[i][j]
} else if (j % 2 !== 0) {
odd += wordsArr[i][j];
}

// can be symplified to
[even, odd][j & 1] += wordsArr[i][j];

Happy coding!

• Thanks! Can you explain the [even, odd][j & 1] += wordsArr[i][j] line to me? This syntax is very new to me. I've never seen it before. I'm used to the "blahblah ? blah1 : blah2 " syntax. – Dream_Cap Aug 11 '17 at 11:19
• @Dream_Cap [even, odd] makes an array with 2 elements. [j & 1] selects an index from the array. j & 1 uses bitwise AND to get same effect as j % 2. Once one has been selected, it adds another character to it. But unless even and odd are already saved in an array, this doesn't work. Their value will be copied into the array and this copy will get the new character added, not the actual variable. – Kruga Aug 11 '17 at 11:33
• I wouldn't say that [even, odd][j & 1] += wordsArr[i][j]; is simpler than the if statement above (though I would remove the else if and replace with an else. Playing with bitwise operators rarely makes code simpler. – Gerrit0 Aug 13 '17 at 19:29

You can make a separate function, which takes a string and returns the two new strings. This simplifies the code by getting rid of nested loops, 2d arrays, and resetting temporary variables.

function processData(input) {
let words = input.split('\n').slice(1).map(splitString);
//This just prints the result in the specified format
words.forEach(e => console.log(e.join(' ')));
}

The new splitString function can also be simplified. You can just use else instead of if else, since it's always true when the first condition is false. There is also no reason to check for the end of the array, since the loop will end when this happens. You don't even have to split the string into an array, since characters in a string for be accessed like array indexes and the both have the .length property.

function splitString(str) {
let even = '';
let odd = '';

for(let i = 0; i < str.length; i++) {
if(i%2 === 0) {
even += str[i];
}
else {
odd += str[i];
}
}

return [even, odd];
}

You can make this function even shorter if you use some of the built-in array functions, like filter or reduce.