Codewars: Reverse or Rotate CodeWars 6 Kyu: Reverse or rotate?

I wrote my Javascript "hello world" on Thursday, so I'm definitely a JS beginner. I do have some experience in Python though, so I'm not a complete novice to programming in general.  

Question


  The input is a string str of digits. Cut the string into chunks (a chunk here is a substring of the initial string) of size sz (ignore the last chunk if its size is less than sz).
  
  If a chunk represents an integer such as the sum of the cubes of its digits is divisible by 2, reverse that chunk; otherwise rotate it to the left by one position. Put together these modified chunks and return the result as a string.
  
  If
  
  
  sz is &lt;= 0 or if str is empty return ""
  sz is greater (&gt;) than the length of str it is impossible to take a chunk of size sz hence return "".
  
  
  Examples:


revrot("123456987654", 6) --&gt; "234561876549"
revrot("123456987653", 6) --&gt; "234561356789"
revrot("66443875", 4) --&gt; "44668753"
revrot("66443875", 8) --&gt; "64438756"
revrot("664438769", 8) --&gt; "67834466"
revrot("123456779", 8) --&gt; "23456771"
revrot("", 8) --&gt; ""
revrot("123456779", 0) --&gt; "" 
revrot("563000655734469485", 4) --&gt; "0365065073456944"


Solution

function revrot(str, sz) 
{
   ln = str.length;
   if(sz &lt; 1 || !str || sz &gt; ln) return "";

   const test = s =&gt; Array.prototype.reduce.call(s, (acc, val) =&gt; acc + Number(val) ** 3, 0) % 2 === 0;
   const reverse = s =&gt; s.split("").reverse().join("");
   const rotate = s =&gt; s.slice(1) + s.slice(0, 1);

   let arr = [];
   for(let i = 0; i &lt; ln; i += sz) arr.push(i+sz &lt;= ln ? str.slice(i, i+sz) : "")
   return arr.map(x =&gt; test(x) ? reverse(x) : rotate(x)).join("");
}
Towards optimization and restructuring

One of downsides of the initial revrot approach is that all nested functions test, reverse and rotate will be redundantly recreated on each revrot call.Instead - define them as top-level functions with meaningful names.

Next, the program lacks 2 edge cases:


when input string contains one single digit and size of required chunk is also 1 (ex. revrot("3", 1)). It's worth to catch that case immediately and return the unchanged input string
when input string contains non-digit character


The intermediate arr array with for loop and slice calls (to get all chunks) is replaced with convenient String.match call on dynamic regex pattern new RegExp(`.{${size}}`, 'g') (matches substrings of specific length/size)



The final optimized approach:



const testCubes = s =&gt; Array.prototype.reduce.call(s, (acc, val) =&gt; acc + Number(val) ** 3, 0) % 2 === 0;
const strReverse = s =&gt; [...s].reverse().join("");
const rotateLeft = s =&gt; s.slice(1) + s.slice(0, 1);


function revrot(str, size) {
    let len = str.length;
    if (size &lt; 1 || !str || size &gt; len) return "";
    if (len === 1 &amp;&amp; size === 1) return str;
    if (/\D/.test(str)) {
        throw Error("Invalid numeric string");
    }
    let pat = new RegExp(`.{${size}}`, 'g');
    return str.match(pat).map(x =&gt; 
        testCubes(x) ? strReverse(x) : rotateLeft(x)
    ).join("");
}


console.log(revrot("123456987654", 6));
console.log(revrot("123456987653", 6));
console.log(revrot("66443875", 8));
console.log(revrot("563000655734469485", 4));
console.log(revrot("1", 1));
console.log(revrot("6644-d3875", 8));